* [PATCH v3 0/7] Replace xe_hmm with gpusvm
@ 2025-04-24 12:18 Matthew Auld
2025-04-24 12:18 ` [PATCH v3 1/7] drm/gpusvm: fix hmm_pfn_to_map_order() usage Matthew Auld
` (6 more replies)
0 siblings, 7 replies; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe; +Cc: dri-devel
As a first step to moving userptr handling over to drm, replace the hmm
usage in xe over to gpusvm, which already offers similar functionality. As
some prep steps we also align on some of the missing pieces that were
already handled in xe_hmm.
v2:
- Rework the gpusvm API based on feedback.
- Unify SVM and userptr vm struct so we use the same notifier lock.
- Drop the mark pages as dirty patch.
- Various other improvements.
v3:
- Further unify common handling of userptr and svm in xe.
--
2.49.0
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 1/7] drm/gpusvm: fix hmm_pfn_to_map_order() usage
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 12:18 ` [PATCH v3 2/7] drm/gpusvm: use more selective dma dir in get_pages() Matthew Auld
` (5 subsequent siblings)
6 siblings, 0 replies; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe; +Cc: dri-devel, Thomas Hellström, Matthew Brost
Handle the case where the hmm range partially covers a huge page (like
2M), otherwise we can potentially end up doing something nasty like
mapping memory which is outside the range, and maybe not even mapped by
the mm. Fix is based on the xe userptr code, which in a future patch
will directly use gpusvm, so needs alignment here.
v2:
- Add kernel-doc (Matt B)
- s/fls/ilog2/ (Thomas)
Reported-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/gpu/drm/drm_gpusvm.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index 38431e8360e7..a2842a112ba0 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -817,6 +817,35 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm,
return range;
}
+/**
+ * drm_gpusvm_hmm_pfn_to_order() - Get the largest CPU mapping order.
+ * @hmm_pfn: The current hmm_pfn.
+ * @hmm_pfn_index: Index of the @hmm_pfn within the pfn array.
+ * @npages: Number of pages within the pfn array i.e the hmm range size.
+ *
+ * To allow skipping PFNs with the same flags (like when they belong to
+ * the same huge PTE) when looping over the pfn array, take a given a hmm_pfn,
+ * and return the largest order that will fit inside the CPU PTE, but also
+ * crucially accounting for the original hmm range boundaries.
+ *
+ * Return: The largest order that will safely fit within the size of the hmm_pfn
+ * CPU PTE.
+ */
+static unsigned int drm_gpusvm_hmm_pfn_to_order(unsigned long hmm_pfn,
+ unsigned long hmm_pfn_index,
+ unsigned long npages)
+{
+ unsigned long size;
+
+ size = 1UL << hmm_pfn_to_map_order(hmm_pfn);
+ size -= (hmm_pfn & ~HMM_PFN_FLAGS) & (size - 1);
+ hmm_pfn_index += size;
+ if (hmm_pfn_index > npages)
+ size -= (hmm_pfn_index - npages);
+
+ return ilog2(size);
+}
+
/**
* drm_gpusvm_check_pages() - Check pages
* @gpusvm: Pointer to the GPU SVM structure
@@ -875,7 +904,7 @@ static bool drm_gpusvm_check_pages(struct drm_gpusvm *gpusvm,
err = -EFAULT;
goto err_free;
}
- i += 0x1 << hmm_pfn_to_map_order(pfns[i]);
+ i += 0x1 << drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages);
}
err_free:
@@ -1408,7 +1437,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
for (i = 0, j = 0; i < npages; ++j) {
struct page *page = hmm_pfn_to_page(pfns[i]);
- order = hmm_pfn_to_map_order(pfns[i]);
+ order = drm_gpusvm_hmm_pfn_to_order(pfns[i], i, npages);
if (is_device_private_page(page) ||
is_device_coherent_page(page)) {
if (zdd != page->zone_device_data && i > 0) {
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 2/7] drm/gpusvm: use more selective dma dir in get_pages()
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
2025-04-24 12:18 ` [PATCH v3 1/7] drm/gpusvm: fix hmm_pfn_to_map_order() usage Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 12:18 ` [PATCH v3 3/7] drm/gpusvm: pull out drm_gpusvm_pages substructure Matthew Auld
` (4 subsequent siblings)
6 siblings, 0 replies; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe; +Cc: dri-devel, Thomas Hellström, Matthew Brost
If we are only reading the memory then from the device pov the direction
can be DMA_TO_DEVICE. This aligns with the xe-userptr code. Using the
most restrictive data direction to represent the access is normally a
good idea.
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/drm_gpusvm.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index a2842a112ba0..d40a01524387 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -1363,6 +1363,8 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
int err = 0;
struct dev_pagemap *pagemap;
struct drm_pagemap *dpagemap;
+ enum dma_data_direction dma_dir = ctx->read_only ? DMA_TO_DEVICE :
+ DMA_BIDIRECTIONAL;
retry:
hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
@@ -1467,7 +1469,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
dpagemap->ops->device_map(dpagemap,
gpusvm->drm->dev,
page, order,
- DMA_BIDIRECTIONAL);
+ dma_dir);
if (dma_mapping_error(gpusvm->drm->dev,
range->dma_addr[j].addr)) {
err = -EFAULT;
@@ -1486,7 +1488,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
addr = dma_map_page(gpusvm->drm->dev,
page, 0,
PAGE_SIZE << order,
- DMA_BIDIRECTIONAL);
+ dma_dir);
if (dma_mapping_error(gpusvm->drm->dev, addr)) {
err = -EFAULT;
goto err_unmap;
@@ -1494,7 +1496,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
range->dma_addr[j] = drm_pagemap_device_addr_encode
(addr, DRM_INTERCONNECT_SYSTEM, order,
- DMA_BIDIRECTIONAL);
+ dma_dir);
}
i += 1 << order;
num_dma_mapped = i;
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 3/7] drm/gpusvm: pull out drm_gpusvm_pages substructure
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
2025-04-24 12:18 ` [PATCH v3 1/7] drm/gpusvm: fix hmm_pfn_to_map_order() usage Matthew Auld
2025-04-24 12:18 ` [PATCH v3 2/7] drm/gpusvm: use more selective dma dir in get_pages() Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 12:18 ` [PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct Matthew Auld
` (3 subsequent siblings)
6 siblings, 0 replies; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe; +Cc: dri-devel, Matthew Brost, Thomas Hellström
Pull the pages stuff from the svm range into its own substructure, with
the idea of having the main pages related routines, like get_pages(),
unmap_pages() and free_pages() all operating on some lower level
structures, which can then be re-used for stuff like userptr.
v2:
- Move seq into pages struct (Matt B)
Suggested-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/drm_gpusvm.c | 66 ++++++++++++++++++++----------------
drivers/gpu/drm/xe/xe_pt.c | 2 +-
drivers/gpu/drm/xe/xe_svm.c | 8 ++---
drivers/gpu/drm/xe/xe_svm.h | 6 ++--
include/drm/drm_gpusvm.h | 53 +++++++++++++++++------------
5 files changed, 76 insertions(+), 59 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index d40a01524387..ef38017d2159 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -811,8 +811,8 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm,
range->itree.start = ALIGN_DOWN(fault_addr, chunk_size);
range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1;
INIT_LIST_HEAD(&range->entry);
- range->notifier_seq = LONG_MAX;
- range->flags.migrate_devmem = migrate_devmem ? 1 : 0;
+ range->pages.notifier_seq = LONG_MAX;
+ range->pages.flags.migrate_devmem = migrate_devmem ? 1 : 0;
return range;
}
@@ -1140,15 +1140,16 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range,
unsigned long npages)
{
- unsigned long i, j;
- struct drm_pagemap *dpagemap = range->dpagemap;
+ struct drm_gpusvm_pages *svm_pages = &range->pages;
+ struct drm_pagemap *dpagemap = svm_pages->dpagemap;
struct device *dev = gpusvm->drm->dev;
+ unsigned long i, j;
lockdep_assert_held(&gpusvm->notifier_lock);
- if (range->flags.has_dma_mapping) {
+ if (svm_pages->flags.has_dma_mapping) {
for (i = 0, j = 0; i < npages; j++) {
- struct drm_pagemap_device_addr *addr = &range->dma_addr[j];
+ struct drm_pagemap_device_addr *addr = &svm_pages->dma_addr[j];
if (addr->proto == DRM_INTERCONNECT_SYSTEM)
dma_unmap_page(dev,
@@ -1160,9 +1161,9 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
dev, *addr);
i += 1 << addr->order;
}
- range->flags.has_devmem_pages = false;
- range->flags.has_dma_mapping = false;
- range->dpagemap = NULL;
+ svm_pages->flags.has_devmem_pages = false;
+ svm_pages->flags.has_dma_mapping = false;
+ svm_pages->dpagemap = NULL;
}
}
@@ -1176,11 +1177,13 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
static void drm_gpusvm_range_free_pages(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range)
{
+ struct drm_gpusvm_pages *svm_pages = &range->pages;
+
lockdep_assert_held(&gpusvm->notifier_lock);
- if (range->dma_addr) {
- kvfree(range->dma_addr);
- range->dma_addr = NULL;
+ if (svm_pages->dma_addr) {
+ kvfree(svm_pages->dma_addr);
+ svm_pages->dma_addr = NULL;
}
}
@@ -1291,9 +1294,11 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range)
{
+ struct drm_gpusvm_pages *svm_pages = &range->pages;
+
lockdep_assert_held(&gpusvm->notifier_lock);
- return range->flags.has_devmem_pages || range->flags.has_dma_mapping;
+ return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
@@ -1311,9 +1316,10 @@ static bool
drm_gpusvm_range_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range)
{
+ struct drm_gpusvm_pages *svm_pages = &range->pages;
bool pages_valid;
- if (!range->dma_addr)
+ if (!svm_pages->dma_addr)
return false;
drm_gpusvm_notifier_lock(gpusvm);
@@ -1340,6 +1346,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range,
const struct drm_gpusvm_ctx *ctx)
{
+ struct drm_gpusvm_pages *svm_pages = &range->pages;
struct mmu_interval_notifier *notifier = &range->notifier->notifier;
struct hmm_range hmm_range = {
.default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
@@ -1409,7 +1416,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
*/
drm_gpusvm_notifier_lock(gpusvm);
- if (range->flags.unmapped) {
+ if (svm_pages->flags.unmapped) {
drm_gpusvm_notifier_unlock(gpusvm);
err = -EFAULT;
goto err_free;
@@ -1421,13 +1428,12 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
goto retry;
}
- if (!range->dma_addr) {
+ if (!svm_pages->dma_addr) {
/* Unlock and restart mapping to allocate memory. */
drm_gpusvm_notifier_unlock(gpusvm);
- range->dma_addr = kvmalloc_array(npages,
- sizeof(*range->dma_addr),
- GFP_KERNEL);
- if (!range->dma_addr) {
+ svm_pages->dma_addr =
+ kvmalloc_array(npages, sizeof(*svm_pages->dma_addr), GFP_KERNEL);
+ if (!svm_pages->dma_addr) {
err = -ENOMEM;
goto err_free;
}
@@ -1465,13 +1471,13 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
goto err_unmap;
}
}
- range->dma_addr[j] =
+ svm_pages->dma_addr[j] =
dpagemap->ops->device_map(dpagemap,
gpusvm->drm->dev,
page, order,
dma_dir);
if (dma_mapping_error(gpusvm->drm->dev,
- range->dma_addr[j].addr)) {
+ svm_pages->dma_addr[j].addr)) {
err = -EFAULT;
goto err_unmap;
}
@@ -1494,7 +1500,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
goto err_unmap;
}
- range->dma_addr[j] = drm_pagemap_device_addr_encode
+ svm_pages->dma_addr[j] = drm_pagemap_device_addr_encode
(addr, DRM_INTERCONNECT_SYSTEM, order,
dma_dir);
}
@@ -1502,16 +1508,16 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
num_dma_mapped = i;
}
- range->flags.has_dma_mapping = true;
+ svm_pages->flags.has_dma_mapping = true;
if (zdd) {
- range->flags.has_devmem_pages = true;
- range->dpagemap = dpagemap;
+ svm_pages->flags.has_devmem_pages = true;
+ svm_pages->dpagemap = dpagemap;
}
drm_gpusvm_notifier_unlock(gpusvm);
kvfree(pfns);
set_seqno:
- range->notifier_seq = hmm_range.notifier_seq;
+ svm_pages->notifier_seq = hmm_range.notifier_seq;
return 0;
@@ -1718,7 +1724,7 @@ int drm_gpusvm_migrate_to_devmem(struct drm_gpusvm *gpusvm,
mmap_assert_locked(gpusvm->mm);
- if (!range->flags.migrate_devmem)
+ if (!range->pages.flags.migrate_devmem)
return -EINVAL;
if (!ops->populate_devmem_pfn || !ops->copy_to_devmem ||
@@ -2247,10 +2253,10 @@ void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
{
lockdep_assert_held_write(&range->gpusvm->notifier_lock);
- range->flags.unmapped = true;
+ range->pages.flags.unmapped = true;
if (drm_gpusvm_range_start(range) < mmu_range->start ||
drm_gpusvm_range_end(range) > mmu_range->end)
- range->flags.partial_unmap = true;
+ range->pages.flags.partial_unmap = true;
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_set_unmapped);
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index b42cf5d1b20c..5cccfd9cc3e9 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -725,7 +725,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
return -EAGAIN;
}
if (xe_svm_range_has_dma_mapping(range)) {
- xe_res_first_dma(range->base.dma_addr, 0,
+ xe_res_first_dma(range->base.pages.dma_addr, 0,
range->base.itree.last + 1 - range->base.itree.start,
&curs);
xe_svm_range_debug(range, "BIND PREPARE - MIXED");
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index 890f6b2f40e9..f60c7f587cd6 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -17,7 +17,7 @@
static bool xe_svm_range_in_vram(struct xe_svm_range *range)
{
/* Not reliable without notifier lock */
- return range->base.flags.has_devmem_pages;
+ return range->base.pages.flags.has_devmem_pages;
}
static bool xe_svm_range_has_vram_binding(struct xe_svm_range *range)
@@ -59,7 +59,7 @@ static unsigned long xe_svm_range_size(struct xe_svm_range *range)
(r__)->base.gpusvm, \
xe_svm_range_in_vram((r__)) ? 1 : 0, \
xe_svm_range_has_vram_binding((r__)) ? 1 : 0, \
- (r__)->base.notifier_seq, \
+ (r__)->base.pages.notifier_seq, \
xe_svm_range_start((r__)), xe_svm_range_end((r__)), \
xe_svm_range_size((r__)))
@@ -135,7 +135,7 @@ xe_svm_range_notifier_event_begin(struct xe_vm *vm, struct drm_gpusvm_range *r,
range_debug(range, "NOTIFIER");
/* Skip if already unmapped or if no binding exist */
- if (range->base.flags.unmapped || !range->tile_present)
+ if (range->base.pages.flags.unmapped || !range->tile_present)
return 0;
range_debug(range, "NOTIFIER - EXECUTE");
@@ -783,7 +783,7 @@ int xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma,
range_debug(range, "PAGE FAULT");
/* XXX: Add migration policy, for now migrate range once */
- if (!range->skip_migrate && range->base.flags.migrate_devmem &&
+ if (!range->skip_migrate && range->base.pages.flags.migrate_devmem &&
xe_svm_range_size(range) >= SZ_64K) {
range->skip_migrate = true;
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index 3d441eb1f7ea..8bc83de87250 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -84,7 +84,7 @@ void xe_svm_range_debug(struct xe_svm_range *range, const char *operation);
static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range)
{
lockdep_assert_held(&range->base.gpusvm->notifier_lock);
- return range->base.flags.has_dma_mapping;
+ return range->base.pages.flags.has_dma_mapping;
}
#define xe_svm_assert_in_notifier(vm__) \
@@ -112,7 +112,9 @@ struct xe_vram_region;
struct xe_svm_range {
struct {
struct interval_tree_node itree;
- const struct drm_pagemap_device_addr *dma_addr;
+ struct {
+ struct drm_pagemap_device_addr *dma_addr;
+ } pages;
} base;
u32 tile_present;
u32 tile_invalidated;
diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
index df120b4d1f83..1b7ed4f4a8e2 100644
--- a/include/drm/drm_gpusvm.h
+++ b/include/drm/drm_gpusvm.h
@@ -185,6 +185,35 @@ struct drm_gpusvm_notifier {
} flags;
};
+/**
+ * struct drm_gpusvm_pages - Structure representing a GPU SVM mapped pages
+ *
+ * @dma_addr: Device address array
+ * @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping.
+ * Note this is assuming only one drm_pagemap per range is allowed.
+ * @notifier_seq: Notifier sequence number of the range's pages
+ * @flags: Flags for range
+ * @flags.migrate_devmem: Flag indicating whether the range can be migrated to device memory
+ * @flags.unmapped: Flag indicating if the range has been unmapped
+ * @flags.partial_unmap: Flag indicating if the range has been partially unmapped
+ * @flags.has_devmem_pages: Flag indicating if the range has devmem pages
+ * @flags.has_dma_mapping: Flag indicating if the range has a DMA mapping
+ */
+struct drm_gpusvm_pages {
+ struct drm_pagemap_device_addr *dma_addr;
+ struct drm_pagemap *dpagemap;
+ unsigned long notifier_seq;
+ struct {
+ /* All flags below must be set upon creation */
+ u16 migrate_devmem : 1;
+ /* All flags below must be set / cleared under notifier lock */
+ u16 unmapped : 1;
+ u16 partial_unmap : 1;
+ u16 has_devmem_pages : 1;
+ u16 has_dma_mapping : 1;
+ } flags;
+};
+
/**
* struct drm_gpusvm_range - Structure representing a GPU SVM range
*
@@ -193,16 +222,7 @@ struct drm_gpusvm_notifier {
* @refcount: Reference count for the range
* @itree: Interval tree node for the range (inserted in GPU SVM notifier)
* @entry: List entry to fast interval tree traversal
- * @notifier_seq: Notifier sequence number of the range's pages
- * @dma_addr: Device address array
- * @dpagemap: The struct drm_pagemap of the device pages we're dma-mapping.
- * Note this is assuming only one drm_pagemap per range is allowed.
- * @flags: Flags for range
- * @flags.migrate_devmem: Flag indicating whether the range can be migrated to device memory
- * @flags.unmapped: Flag indicating if the range has been unmapped
- * @flags.partial_unmap: Flag indicating if the range has been partially unmapped
- * @flags.has_devmem_pages: Flag indicating if the range has devmem pages
- * @flags.has_dma_mapping: Flag indicating if the range has a DMA mapping
+ * @pages: The pages for this range.
*
* This structure represents a GPU SVM range used for tracking memory ranges
* mapped in a DRM device.
@@ -213,18 +233,7 @@ struct drm_gpusvm_range {
struct kref refcount;
struct interval_tree_node itree;
struct list_head entry;
- unsigned long notifier_seq;
- struct drm_pagemap_device_addr *dma_addr;
- struct drm_pagemap *dpagemap;
- struct {
- /* All flags below must be set upon creation */
- u16 migrate_devmem : 1;
- /* All flags below must be set / cleared under notifier lock */
- u16 unmapped : 1;
- u16 partial_unmap : 1;
- u16 has_devmem_pages : 1;
- u16 has_dma_mapping : 1;
- } flags;
+ struct drm_gpusvm_pages pages;
};
/**
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
` (2 preceding siblings ...)
2025-04-24 12:18 ` [PATCH v3 3/7] drm/gpusvm: pull out drm_gpusvm_pages substructure Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 21:47 ` Matthew Brost
2025-04-24 12:18 ` [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API Matthew Auld
` (2 subsequent siblings)
6 siblings, 1 reply; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe; +Cc: dri-devel, Matthew Brost, Thomas Hellström
Refactor the core API of get/unmap/free pages to all operate on
drm_gpusvm_pages. In the next patch we want to export a simplified core
API without needing fully blown svm range etc.
Suggested-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/gpu/drm/drm_gpusvm.c | 161 ++++++++++++++++++++++++-----------
1 file changed, 110 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index ef38017d2159..fbe0d70ef163 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -1128,19 +1128,19 @@ drm_gpusvm_range_find_or_insert(struct drm_gpusvm *gpusvm,
EXPORT_SYMBOL_GPL(drm_gpusvm_range_find_or_insert);
/**
- * __drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range (internal)
+ * __drm_gpusvm_unmap_pages() - Unmap pages associated with GPU SVM pages
+ * (internal)
* @gpusvm: Pointer to the GPU SVM structure
- * @range: Pointer to the GPU SVM range structure
+ * @pages: Pointer to the GPU SVM pages structure
* @npages: Number of pages to unmap
*
- * This function unmap pages associated with a GPU SVM range. Assumes and
+ * This function unmap pages associated with a GPU SVM pages struct. Assumes and
* asserts correct locking is in place when called.
*/
-static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range,
- unsigned long npages)
+static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ unsigned long npages)
{
- struct drm_gpusvm_pages *svm_pages = &range->pages;
struct drm_pagemap *dpagemap = svm_pages->dpagemap;
struct device *dev = gpusvm->drm->dev;
unsigned long i, j;
@@ -1168,17 +1168,15 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
}
/**
- * drm_gpusvm_range_free_pages() - Free pages associated with a GPU SVM range
+ * __drm_gpusvm_free_pages() - Free dma array associated with GPU SVM pages
* @gpusvm: Pointer to the GPU SVM structure
- * @range: Pointer to the GPU SVM range structure
+ * @svm_pages: Pointer to the GPU SVM pages structure
*
* This function frees the dma address array associated with a GPU SVM range.
*/
-static void drm_gpusvm_range_free_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range)
+static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages)
{
- struct drm_gpusvm_pages *svm_pages = &range->pages;
-
lockdep_assert_held(&gpusvm->notifier_lock);
if (svm_pages->dma_addr) {
@@ -1211,8 +1209,8 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
return;
drm_gpusvm_notifier_lock(gpusvm);
- __drm_gpusvm_range_unmap_pages(gpusvm, range, npages);
- drm_gpusvm_range_free_pages(gpusvm, range);
+ __drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages);
+ __drm_gpusvm_free_pages(gpusvm, &range->pages);
__drm_gpusvm_range_remove(notifier, range);
drm_gpusvm_notifier_unlock(gpusvm);
@@ -1277,6 +1275,28 @@ void drm_gpusvm_range_put(struct drm_gpusvm_range *range)
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
+/**
+ * drm_gpusvm_pages_valid() - GPU SVM range pages valid
+ * @gpusvm: Pointer to the GPU SVM structure
+ * @svm_pages: Pointer to the GPU SVM pages structure
+ *
+ * This function determines if a GPU SVM range pages are valid. Expected be
+ * called holding gpusvm->notifier_lock and as the last step before committing a
+ * GPU binding. This is akin to a notifier seqno check in the HMM documentation
+ * but due to wider notifiers (i.e., notifiers which span multiple ranges) this
+ * function is required for finer grained checking (i.e., per range) if pages
+ * are valid.
+ *
+ * Return: True if GPU SVM range has valid pages, False otherwise
+ */
+static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages)
+{
+ lockdep_assert_held(&gpusvm->notifier_lock);
+
+ return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
+}
+
/**
* drm_gpusvm_range_pages_valid() - GPU SVM range pages valid
* @gpusvm: Pointer to the GPU SVM structure
@@ -1294,11 +1314,7 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
struct drm_gpusvm_range *range)
{
- struct drm_gpusvm_pages *svm_pages = &range->pages;
-
- lockdep_assert_held(&gpusvm->notifier_lock);
-
- return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
+ return drm_gpusvm_pages_valid(gpusvm, &range->pages);
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
@@ -1312,57 +1328,59 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
*
* Return: True if GPU SVM range has valid pages, False otherwise
*/
-static bool
-drm_gpusvm_range_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range)
+static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages)
{
- struct drm_gpusvm_pages *svm_pages = &range->pages;
bool pages_valid;
if (!svm_pages->dma_addr)
return false;
drm_gpusvm_notifier_lock(gpusvm);
- pages_valid = drm_gpusvm_range_pages_valid(gpusvm, range);
+ pages_valid = drm_gpusvm_pages_valid(gpusvm, svm_pages);
if (!pages_valid)
- drm_gpusvm_range_free_pages(gpusvm, range);
+ __drm_gpusvm_free_pages(gpusvm, svm_pages);
drm_gpusvm_notifier_unlock(gpusvm);
return pages_valid;
}
/**
- * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
+ * drm_gpusvm_get_pages() - Get pages and populate GPU SVM pages struct
* @gpusvm: Pointer to the GPU SVM structure
- * @range: Pointer to the GPU SVM range structure
+ * @svm_pages: The SVM pages to populate. This will contain the dma-addresses
+ * @mm: The mm corresponding to the CPU range
+ * @notifier: The corresponding notifier for the given CPU range
+ * @pages_start: Start CPU address for the pages
+ * @pages_end: End CPU address for the pages (exclusive)
* @ctx: GPU SVM context
*
- * This function gets pages for a GPU SVM range and ensures they are mapped for
- * DMA access.
+ * This function gets and maps pages for CPU range and ensures they are
+ * mapped for DMA access.
*
* Return: 0 on success, negative error code on failure.
*/
-int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_range *range,
- const struct drm_gpusvm_ctx *ctx)
+static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ struct mm_struct *mm,
+ struct mmu_interval_notifier *notifier,
+ unsigned long pages_start,
+ unsigned long pages_end,
+ const struct drm_gpusvm_ctx *ctx)
{
- struct drm_gpusvm_pages *svm_pages = &range->pages;
- struct mmu_interval_notifier *notifier = &range->notifier->notifier;
struct hmm_range hmm_range = {
.default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
HMM_PFN_REQ_WRITE),
.notifier = notifier,
- .start = drm_gpusvm_range_start(range),
- .end = drm_gpusvm_range_end(range),
+ .start = pages_start,
+ .end = pages_end,
.dev_private_owner = gpusvm->device_private_page_owner,
};
- struct mm_struct *mm = gpusvm->mm;
struct drm_gpusvm_zdd *zdd;
unsigned long timeout =
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
unsigned long i, j;
- unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
- drm_gpusvm_range_end(range));
+ unsigned long npages = npages_in_range(pages_start, pages_end);
unsigned long num_dma_mapped;
unsigned int order = 0;
unsigned long *pfns;
@@ -1375,7 +1393,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
retry:
hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
- if (drm_gpusvm_range_pages_valid_unlocked(gpusvm, range))
+ if (drm_gpusvm_pages_valid_unlocked(gpusvm, svm_pages))
goto set_seqno;
pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
@@ -1522,7 +1540,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
return 0;
err_unmap:
- __drm_gpusvm_range_unmap_pages(gpusvm, range, num_dma_mapped);
+ __drm_gpusvm_unmap_pages(gpusvm, svm_pages, num_dma_mapped);
drm_gpusvm_notifier_unlock(gpusvm);
err_free:
kvfree(pfns);
@@ -1530,8 +1548,57 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
goto retry;
return err;
}
+
+/**
+ * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
+ * @gpusvm: Pointer to the GPU SVM structure
+ * @range: Pointer to the GPU SVM range structure
+ * @ctx: GPU SVM context
+ *
+ * This function gets pages for a GPU SVM range and ensures they are mapped for
+ * DMA access.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_range *range,
+ const struct drm_gpusvm_ctx *ctx)
+{
+ return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm,
+ &range->notifier->notifier,
+ drm_gpusvm_range_start(range),
+ drm_gpusvm_range_end(range), ctx);
+}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
+/**
+ * drm_gpusvm_unmap_pages() - Unmap GPU svm pages
+ * @gpusvm: Pointer to the GPU SVM structure
+ * @pages: Pointer to the GPU SVM pages structure
+ * @ctx: GPU SVM context
+ *
+ * This function unmaps pages associated with a GPU SVM pages struct. If
+ * @in_notifier is set, it is assumed that gpusvm->notifier_lock is held in
+ * write mode; if it is clear, it acquires gpusvm->notifier_lock in read mode.
+ * Must be called in the invalidate() callback of the corresponding notifier for
+ * IOMMU security model.
+ */
+static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ unsigned long npages,
+ const struct drm_gpusvm_ctx *ctx)
+{
+ if (ctx->in_notifier)
+ lockdep_assert_held_write(&gpusvm->notifier_lock);
+ else
+ drm_gpusvm_notifier_lock(gpusvm);
+
+ __drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages);
+
+ if (!ctx->in_notifier)
+ drm_gpusvm_notifier_unlock(gpusvm);
+}
+
/**
* drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
* @gpusvm: Pointer to the GPU SVM structure
@@ -1551,15 +1618,7 @@ void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
drm_gpusvm_range_end(range));
- if (ctx->in_notifier)
- lockdep_assert_held_write(&gpusvm->notifier_lock);
- else
- drm_gpusvm_notifier_lock(gpusvm);
-
- __drm_gpusvm_range_unmap_pages(gpusvm, range, npages);
-
- if (!ctx->in_notifier)
- drm_gpusvm_notifier_unlock(gpusvm);
+ return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx);
}
EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages);
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
` (3 preceding siblings ...)
2025-04-24 12:18 ` [PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 22:01 ` Matthew Brost
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
2025-04-24 12:18 ` [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr Matthew Auld
6 siblings, 1 reply; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe; +Cc: dri-devel, Thomas Hellström, Matthew Brost
Export get/unmap/free pages API. We also need to tweak the SVM init to
allow skipping much of the unneeded parts.
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/drm_gpusvm.c | 66 ++++++++++++++++++++++++++++--------
include/drm/drm_gpusvm.h | 16 +++++++++
2 files changed, 67 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index fbe0d70ef163..0e0a3c995b4b 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -539,6 +539,12 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
*
* This function initializes the GPU SVM.
*
+ * Note: If only using the simple drm_gpusvm_pages API (get/unmap/free),
+ * then only @gpusvm, @name, and @drm are expected. However, the same base
+ * @gpusvm can also be used with both modes together in which case the full
+ * setup is needed, where the core drm_gpusvm_pages API will simply never use
+ * the other fields.
+ *
* Return: 0 on success, a negative error code on failure.
*/
int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
@@ -549,8 +555,16 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
const struct drm_gpusvm_ops *ops,
const unsigned long *chunk_sizes, int num_chunks)
{
- if (!ops->invalidate || !num_chunks)
- return -EINVAL;
+ if (mm) {
+ if (!ops->invalidate || !num_chunks)
+ return -EINVAL;
+ mmgrab(mm);
+ } else {
+ /* No full SVM mode, only core drm_gpusvm_pages API. */
+ if (ops || num_chunks || mm_range || notifier_size ||
+ device_private_page_owner)
+ return -EINVAL;
+ }
gpusvm->name = name;
gpusvm->drm = drm;
@@ -563,7 +577,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
gpusvm->chunk_sizes = chunk_sizes;
gpusvm->num_chunks = num_chunks;
- mmgrab(mm);
gpusvm->root = RB_ROOT_CACHED;
INIT_LIST_HEAD(&gpusvm->notifier_list);
@@ -671,7 +684,8 @@ void drm_gpusvm_fini(struct drm_gpusvm *gpusvm)
drm_gpusvm_range_remove(gpusvm, range);
}
- mmdrop(gpusvm->mm);
+ if (gpusvm->mm)
+ mmdrop(gpusvm->mm);
WARN_ON(!RB_EMPTY_ROOT(&gpusvm->root.rb_root));
}
EXPORT_SYMBOL_GPL(drm_gpusvm_fini);
@@ -1185,6 +1199,27 @@ static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
}
}
+/**
+ * drm_gpusvm_free_pages() - Free dma-mapping associated with GPU SVM pages
+ * struct
+ * @gpusvm: Pointer to the GPU SVM structure
+ * @svm_pages: Pointer to the GPU SVM pages structure
+ * @npages: Number of mapped pages
+ *
+ * This function unmaps and frees the dma address array associated with a GPU
+ * SVM pages struct.
+ */
+void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ unsigned long npages)
+{
+ drm_gpusvm_notifier_lock(gpusvm);
+ __drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages);
+ __drm_gpusvm_free_pages(gpusvm, svm_pages);
+ drm_gpusvm_notifier_unlock(gpusvm);
+}
+EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages);
+
/**
* drm_gpusvm_range_remove() - Remove GPU SVM range
* @gpusvm: Pointer to the GPU SVM structure
@@ -1360,13 +1395,12 @@ static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
*
* Return: 0 on success, negative error code on failure.
*/
-static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_pages *svm_pages,
- struct mm_struct *mm,
- struct mmu_interval_notifier *notifier,
- unsigned long pages_start,
- unsigned long pages_end,
- const struct drm_gpusvm_ctx *ctx)
+int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ struct mm_struct *mm,
+ struct mmu_interval_notifier *notifier,
+ unsigned long pages_start, unsigned long pages_end,
+ const struct drm_gpusvm_ctx *ctx)
{
struct hmm_range hmm_range = {
.default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
@@ -1548,6 +1582,7 @@ static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
goto retry;
return err;
}
+EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages);
/**
* drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
@@ -1583,10 +1618,10 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
* Must be called in the invalidate() callback of the corresponding notifier for
* IOMMU security model.
*/
-static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
- struct drm_gpusvm_pages *svm_pages,
- unsigned long npages,
- const struct drm_gpusvm_ctx *ctx)
+void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ unsigned long npages,
+ const struct drm_gpusvm_ctx *ctx)
{
if (ctx->in_notifier)
lockdep_assert_held_write(&gpusvm->notifier_lock);
@@ -1598,6 +1633,7 @@ static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
if (!ctx->in_notifier)
drm_gpusvm_notifier_unlock(gpusvm);
}
+EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages);
/**
* drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
index 1b7ed4f4a8e2..611aaba1ac80 100644
--- a/include/drm/drm_gpusvm.h
+++ b/include/drm/drm_gpusvm.h
@@ -370,6 +370,22 @@ void drm_gpusvm_devmem_init(struct drm_gpusvm_devmem *devmem_allocation,
const struct drm_gpusvm_devmem_ops *ops,
struct drm_pagemap *dpagemap, size_t size);
+int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ struct mm_struct *mm,
+ struct mmu_interval_notifier *notifier,
+ unsigned long pages_start, unsigned long pages_end,
+ const struct drm_gpusvm_ctx *ctx);
+
+void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ unsigned long npages,
+ const struct drm_gpusvm_ctx *ctx);
+
+void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_pages *svm_pages,
+ unsigned long npages);
+
#ifdef CONFIG_LOCKDEP
/**
* drm_gpusvm_driver_set_lock() - Set the lock protecting accesses to GPU SVM
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
` (4 preceding siblings ...)
2025-04-24 12:18 ` [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 14:21 ` kernel test robot
` (4 more replies)
2025-04-24 12:18 ` [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr Matthew Auld
6 siblings, 5 replies; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe
Cc: dri-devel, Himal Prasad Ghimiray, Thomas Hellström,
Matthew Brost
Goal here is cut over to gpusvm and remove xe_hmm, relying instead on
common code. The core facilities we need are get_pages(), unmap_pages()
and free_pages() for a given useptr range, plus a vm level notifier
lock, which is now provided by gpusvm.
v2:
- Reuse the same SVM vm struct we use for full SVM, that way we can
use the same lock (Matt B & Himal)
v3:
- Re-use svm_init/fini for userptr.
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
---
drivers/gpu/drm/xe/Kconfig | 3 +-
drivers/gpu/drm/xe/Makefile | 1 -
drivers/gpu/drm/xe/xe_exec.c | 4 +-
drivers/gpu/drm/xe/xe_hmm.c | 325 -------------------------------
drivers/gpu/drm/xe/xe_hmm.h | 18 --
drivers/gpu/drm/xe/xe_pt.c | 22 +--
drivers/gpu/drm/xe/xe_svm.c | 32 +--
drivers/gpu/drm/xe/xe_svm.h | 6 +-
drivers/gpu/drm/xe/xe_vm.c | 86 ++++----
drivers/gpu/drm/xe/xe_vm_types.h | 26 +--
10 files changed, 92 insertions(+), 431 deletions(-)
delete mode 100644 drivers/gpu/drm/xe/xe_hmm.c
delete mode 100644 drivers/gpu/drm/xe/xe_hmm.h
diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
index 9bce047901b2..1e63dde76c55 100644
--- a/drivers/gpu/drm/xe/Kconfig
+++ b/drivers/gpu/drm/xe/Kconfig
@@ -43,7 +43,7 @@ config DRM_XE
select MMU_NOTIFIER
select WANT_DEV_COREDUMP
select AUXILIARY_BUS
- select HMM_MIRROR
+ select DRM_GPUSVM
help
Experimental driver for Intel Xe series GPUs
@@ -79,7 +79,6 @@ config DRM_XE_GPUSVM
depends on !UML
depends on DEVICE_PRIVATE
default y
- select DRM_GPUSVM
help
Enable this option if you want support for CPU to GPU address
mirroring.
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 3ecac0a38b82..f1123be158f8 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -124,7 +124,6 @@ xe-y += xe_bb.o \
xe_wait_user_fence.o \
xe_wopcm.o
-xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
# graphics hardware monitoring (HWMON) support
diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
index b75adfc99fb7..c0ce681076d5 100644
--- a/drivers/gpu/drm/xe/xe_exec.c
+++ b/drivers/gpu/drm/xe/xe_exec.c
@@ -294,7 +294,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
if (err)
goto err_put_job;
- err = down_read_interruptible(&vm->userptr.notifier_lock);
+ err = down_read_interruptible(&vm->svm.gpusvm.notifier_lock);
if (err)
goto err_put_job;
@@ -336,7 +336,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
err_repin:
if (!xe_vm_in_lr_mode(vm))
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
err_put_job:
if (err)
xe_sched_job_put(job);
diff --git a/drivers/gpu/drm/xe/xe_hmm.c b/drivers/gpu/drm/xe/xe_hmm.c
deleted file mode 100644
index 57b71956ddf4..000000000000
--- a/drivers/gpu/drm/xe/xe_hmm.c
+++ /dev/null
@@ -1,325 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2024 Intel Corporation
- */
-
-#include <linux/scatterlist.h>
-#include <linux/mmu_notifier.h>
-#include <linux/dma-mapping.h>
-#include <linux/memremap.h>
-#include <linux/swap.h>
-#include <linux/hmm.h>
-#include <linux/mm.h>
-#include "xe_hmm.h"
-#include "xe_vm.h"
-#include "xe_bo.h"
-
-static u64 xe_npages_in_range(unsigned long start, unsigned long end)
-{
- return (end - start) >> PAGE_SHIFT;
-}
-
-static int xe_alloc_sg(struct xe_device *xe, struct sg_table *st,
- struct hmm_range *range, struct rw_semaphore *notifier_sem)
-{
- unsigned long i, npages, hmm_pfn;
- unsigned long num_chunks = 0;
- int ret;
-
- /* HMM docs says this is needed. */
- ret = down_read_interruptible(notifier_sem);
- if (ret)
- return ret;
-
- if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) {
- up_read(notifier_sem);
- return -EAGAIN;
- }
-
- npages = xe_npages_in_range(range->start, range->end);
- for (i = 0; i < npages;) {
- unsigned long len;
-
- hmm_pfn = range->hmm_pfns[i];
- xe_assert(xe, hmm_pfn & HMM_PFN_VALID);
-
- len = 1UL << hmm_pfn_to_map_order(hmm_pfn);
-
- /* If order > 0 the page may extend beyond range->start */
- len -= (hmm_pfn & ~HMM_PFN_FLAGS) & (len - 1);
- i += len;
- num_chunks++;
- }
- up_read(notifier_sem);
-
- return sg_alloc_table(st, num_chunks, GFP_KERNEL);
-}
-
-/**
- * xe_build_sg() - build a scatter gather table for all the physical pages/pfn
- * in a hmm_range. dma-map pages if necessary. dma-address is save in sg table
- * and will be used to program GPU page table later.
- * @xe: the xe device who will access the dma-address in sg table
- * @range: the hmm range that we build the sg table from. range->hmm_pfns[]
- * has the pfn numbers of pages that back up this hmm address range.
- * @st: pointer to the sg table.
- * @notifier_sem: The xe notifier lock.
- * @write: whether we write to this range. This decides dma map direction
- * for system pages. If write we map it bi-diretional; otherwise
- * DMA_TO_DEVICE
- *
- * All the contiguous pfns will be collapsed into one entry in
- * the scatter gather table. This is for the purpose of efficiently
- * programming GPU page table.
- *
- * The dma_address in the sg table will later be used by GPU to
- * access memory. So if the memory is system memory, we need to
- * do a dma-mapping so it can be accessed by GPU/DMA.
- *
- * FIXME: This function currently only support pages in system
- * memory. If the memory is GPU local memory (of the GPU who
- * is going to access memory), we need gpu dpa (device physical
- * address), and there is no need of dma-mapping. This is TBD.
- *
- * FIXME: dma-mapping for peer gpu device to access remote gpu's
- * memory. Add this when you support p2p
- *
- * This function allocates the storage of the sg table. It is
- * caller's responsibility to free it calling sg_free_table.
- *
- * Returns 0 if successful; -ENOMEM if fails to allocate memory
- */
-static int xe_build_sg(struct xe_device *xe, struct hmm_range *range,
- struct sg_table *st,
- struct rw_semaphore *notifier_sem,
- bool write)
-{
- unsigned long npages = xe_npages_in_range(range->start, range->end);
- struct device *dev = xe->drm.dev;
- struct scatterlist *sgl;
- struct page *page;
- unsigned long i, j;
-
- lockdep_assert_held(notifier_sem);
-
- i = 0;
- for_each_sg(st->sgl, sgl, st->nents, j) {
- unsigned long hmm_pfn, size;
-
- hmm_pfn = range->hmm_pfns[i];
- page = hmm_pfn_to_page(hmm_pfn);
- xe_assert(xe, !is_device_private_page(page));
-
- size = 1UL << hmm_pfn_to_map_order(hmm_pfn);
- size -= page_to_pfn(page) & (size - 1);
- i += size;
-
- if (unlikely(j == st->nents - 1)) {
- xe_assert(xe, i >= npages);
- if (i > npages)
- size -= (i - npages);
-
- sg_mark_end(sgl);
- } else {
- xe_assert(xe, i < npages);
- }
-
- sg_set_page(sgl, page, size << PAGE_SHIFT, 0);
- }
-
- return dma_map_sgtable(dev, st, write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE,
- DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_NO_KERNEL_MAPPING);
-}
-
-static void xe_hmm_userptr_set_mapped(struct xe_userptr_vma *uvma)
-{
- struct xe_userptr *userptr = &uvma->userptr;
- struct xe_vm *vm = xe_vma_vm(&uvma->vma);
-
- lockdep_assert_held_write(&vm->lock);
- lockdep_assert_held(&vm->userptr.notifier_lock);
-
- mutex_lock(&userptr->unmap_mutex);
- xe_assert(vm->xe, !userptr->mapped);
- userptr->mapped = true;
- mutex_unlock(&userptr->unmap_mutex);
-}
-
-void xe_hmm_userptr_unmap(struct xe_userptr_vma *uvma)
-{
- struct xe_userptr *userptr = &uvma->userptr;
- struct xe_vma *vma = &uvma->vma;
- bool write = !xe_vma_read_only(vma);
- struct xe_vm *vm = xe_vma_vm(vma);
- struct xe_device *xe = vm->xe;
-
- if (!lockdep_is_held_type(&vm->userptr.notifier_lock, 0) &&
- !lockdep_is_held_type(&vm->lock, 0) &&
- !(vma->gpuva.flags & XE_VMA_DESTROYED)) {
- /* Don't unmap in exec critical section. */
- xe_vm_assert_held(vm);
- /* Don't unmap while mapping the sg. */
- lockdep_assert_held(&vm->lock);
- }
-
- mutex_lock(&userptr->unmap_mutex);
- if (userptr->sg && userptr->mapped)
- dma_unmap_sgtable(xe->drm.dev, userptr->sg,
- write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE, 0);
- userptr->mapped = false;
- mutex_unlock(&userptr->unmap_mutex);
-}
-
-/**
- * xe_hmm_userptr_free_sg() - Free the scatter gather table of userptr
- * @uvma: the userptr vma which hold the scatter gather table
- *
- * With function xe_userptr_populate_range, we allocate storage of
- * the userptr sg table. This is a helper function to free this
- * sg table, and dma unmap the address in the table.
- */
-void xe_hmm_userptr_free_sg(struct xe_userptr_vma *uvma)
-{
- struct xe_userptr *userptr = &uvma->userptr;
-
- xe_assert(xe_vma_vm(&uvma->vma)->xe, userptr->sg);
- xe_hmm_userptr_unmap(uvma);
- sg_free_table(userptr->sg);
- userptr->sg = NULL;
-}
-
-/**
- * xe_hmm_userptr_populate_range() - Populate physical pages of a virtual
- * address range
- *
- * @uvma: userptr vma which has information of the range to populate.
- * @is_mm_mmap_locked: True if mmap_read_lock is already acquired by caller.
- *
- * This function populate the physical pages of a virtual
- * address range. The populated physical pages is saved in
- * userptr's sg table. It is similar to get_user_pages but call
- * hmm_range_fault.
- *
- * This function also read mmu notifier sequence # (
- * mmu_interval_read_begin), for the purpose of later
- * comparison (through mmu_interval_read_retry).
- *
- * This must be called with mmap read or write lock held.
- *
- * This function allocates the storage of the userptr sg table.
- * It is caller's responsibility to free it calling sg_free_table.
- *
- * returns: 0 for success; negative error no on failure
- */
-int xe_hmm_userptr_populate_range(struct xe_userptr_vma *uvma,
- bool is_mm_mmap_locked)
-{
- unsigned long timeout =
- jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
- unsigned long *pfns;
- struct xe_userptr *userptr;
- struct xe_vma *vma = &uvma->vma;
- u64 userptr_start = xe_vma_userptr(vma);
- u64 userptr_end = userptr_start + xe_vma_size(vma);
- struct xe_vm *vm = xe_vma_vm(vma);
- struct hmm_range hmm_range = {
- .pfn_flags_mask = 0, /* ignore pfns */
- .default_flags = HMM_PFN_REQ_FAULT,
- .start = userptr_start,
- .end = userptr_end,
- .notifier = &uvma->userptr.notifier,
- .dev_private_owner = vm->xe,
- };
- bool write = !xe_vma_read_only(vma);
- unsigned long notifier_seq;
- u64 npages;
- int ret;
-
- userptr = &uvma->userptr;
-
- if (is_mm_mmap_locked)
- mmap_assert_locked(userptr->notifier.mm);
-
- if (vma->gpuva.flags & XE_VMA_DESTROYED)
- return 0;
-
- notifier_seq = mmu_interval_read_begin(&userptr->notifier);
- if (notifier_seq == userptr->notifier_seq)
- return 0;
-
- if (userptr->sg)
- xe_hmm_userptr_free_sg(uvma);
-
- npages = xe_npages_in_range(userptr_start, userptr_end);
- pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
- if (unlikely(!pfns))
- return -ENOMEM;
-
- if (write)
- hmm_range.default_flags |= HMM_PFN_REQ_WRITE;
-
- if (!mmget_not_zero(userptr->notifier.mm)) {
- ret = -EFAULT;
- goto free_pfns;
- }
-
- hmm_range.hmm_pfns = pfns;
-
- while (true) {
- hmm_range.notifier_seq = mmu_interval_read_begin(&userptr->notifier);
-
- if (!is_mm_mmap_locked)
- mmap_read_lock(userptr->notifier.mm);
-
- ret = hmm_range_fault(&hmm_range);
-
- if (!is_mm_mmap_locked)
- mmap_read_unlock(userptr->notifier.mm);
-
- if (ret == -EBUSY) {
- if (time_after(jiffies, timeout))
- break;
-
- continue;
- }
- break;
- }
-
- mmput(userptr->notifier.mm);
-
- if (ret)
- goto free_pfns;
-
- ret = xe_alloc_sg(vm->xe, &userptr->sgt, &hmm_range, &vm->userptr.notifier_lock);
- if (ret)
- goto free_pfns;
-
- ret = down_read_interruptible(&vm->userptr.notifier_lock);
- if (ret)
- goto free_st;
-
- if (mmu_interval_read_retry(hmm_range.notifier, hmm_range.notifier_seq)) {
- ret = -EAGAIN;
- goto out_unlock;
- }
-
- ret = xe_build_sg(vm->xe, &hmm_range, &userptr->sgt,
- &vm->userptr.notifier_lock, write);
- if (ret)
- goto out_unlock;
-
- userptr->sg = &userptr->sgt;
- xe_hmm_userptr_set_mapped(uvma);
- userptr->notifier_seq = hmm_range.notifier_seq;
- up_read(&vm->userptr.notifier_lock);
- kvfree(pfns);
- return 0;
-
-out_unlock:
- up_read(&vm->userptr.notifier_lock);
-free_st:
- sg_free_table(&userptr->sgt);
-free_pfns:
- kvfree(pfns);
- return ret;
-}
diff --git a/drivers/gpu/drm/xe/xe_hmm.h b/drivers/gpu/drm/xe/xe_hmm.h
deleted file mode 100644
index 0ea98d8e7bbc..000000000000
--- a/drivers/gpu/drm/xe/xe_hmm.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: MIT
- *
- * Copyright © 2024 Intel Corporation
- */
-
-#ifndef _XE_HMM_H_
-#define _XE_HMM_H_
-
-#include <linux/types.h>
-
-struct xe_userptr_vma;
-
-int xe_hmm_userptr_populate_range(struct xe_userptr_vma *uvma, bool is_mm_mmap_locked);
-
-void xe_hmm_userptr_free_sg(struct xe_userptr_vma *uvma);
-
-void xe_hmm_userptr_unmap(struct xe_userptr_vma *uvma);
-#endif
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 5cccfd9cc3e9..ff898e518afd 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -756,8 +756,8 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
if (!xe_vma_is_null(vma) && !range) {
if (xe_vma_is_userptr(vma))
- xe_res_first_sg(to_userptr_vma(vma)->userptr.sg, 0,
- xe_vma_size(vma), &curs);
+ xe_res_first_dma(to_userptr_vma(vma)->userptr.pages.dma_addr, 0,
+ xe_vma_size(vma), &curs);
else if (xe_bo_is_vram(bo) || xe_bo_is_stolen(bo))
xe_res_first(bo->ttm.resource, xe_vma_bo_offset(vma),
xe_vma_size(vma), &curs);
@@ -1028,7 +1028,7 @@ static void xe_pt_commit_locks_assert(struct xe_vma *vma)
xe_pt_commit_prepare_locks_assert(vma);
if (xe_vma_is_userptr(vma))
- lockdep_assert_held_read(&vm->userptr.notifier_lock);
+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
}
static void xe_pt_commit(struct xe_vma *vma,
@@ -1368,7 +1368,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
struct xe_userptr_vma *uvma;
unsigned long notifier_seq;
- lockdep_assert_held_read(&vm->userptr.notifier_lock);
+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
if (!xe_vma_is_userptr(vma))
return 0;
@@ -1377,7 +1377,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
if (xe_pt_userptr_inject_eagain(uvma))
xe_vma_userptr_force_invalidate(uvma);
- notifier_seq = uvma->userptr.notifier_seq;
+ notifier_seq = uvma->userptr.pages.notifier_seq;
if (!mmu_interval_read_retry(&uvma->userptr.notifier,
notifier_seq))
@@ -1398,7 +1398,7 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
{
int err = 0;
- lockdep_assert_held_read(&vm->userptr.notifier_lock);
+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
switch (op->base.op) {
case DRM_GPUVA_OP_MAP:
@@ -1439,12 +1439,12 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
if (err)
return err;
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
list_for_each_entry(op, &vops->list, link) {
err = op_check_userptr(vm, op, pt_update_ops);
if (err) {
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
break;
}
}
@@ -2171,7 +2171,7 @@ static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
if (invalidate_on_bind)
vma->tile_invalidated |= BIT(tile->id);
if (xe_vma_is_userptr(vma)) {
- lockdep_assert_held_read(&vm->userptr.notifier_lock);
+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
to_userptr_vma(vma)->userptr.initial_bind = true;
}
@@ -2207,7 +2207,7 @@ static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
if (!vma->tile_present) {
list_del_init(&vma->combined_links.rebind);
if (xe_vma_is_userptr(vma)) {
- lockdep_assert_held_read(&vm->userptr.notifier_lock);
+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
spin_lock(&vm->userptr.invalidated_lock);
list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link);
@@ -2456,7 +2456,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
if (pt_update_ops->needs_svm_lock)
xe_svm_notifier_unlock(vm);
if (pt_update_ops->needs_userptr_lock)
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
return fence;
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index f60c7f587cd6..10ec237ec88c 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -606,22 +606,26 @@ int xe_svm_init(struct xe_vm *vm)
{
int err;
- spin_lock_init(&vm->svm.garbage_collector.lock);
- INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
- INIT_WORK(&vm->svm.garbage_collector.work,
- xe_svm_garbage_collector_work_func);
+ if (vm->flags & XE_VM_FLAG_FAULT_MODE) {
+ spin_lock_init(&vm->svm.garbage_collector.lock);
+ INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
+ INIT_WORK(&vm->svm.garbage_collector.work,
+ xe_svm_garbage_collector_work_func);
- err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
- current->mm, xe_svm_devm_owner(vm->xe), 0,
- vm->size, xe_modparam.svm_notifier_size * SZ_1M,
- &gpusvm_ops, fault_chunk_sizes,
- ARRAY_SIZE(fault_chunk_sizes));
- if (err)
- return err;
+ err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
+ current->mm, xe_svm_devm_owner(vm->xe), 0,
+ vm->size,
+ xe_modparam.svm_notifier_size * SZ_1M,
+ &gpusvm_ops, fault_chunk_sizes,
+ ARRAY_SIZE(fault_chunk_sizes));
+ drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
+ } else {
+ err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
+ &vm->xe->drm, NULL, NULL, 0, 0, 0, NULL,
+ NULL, 0);
+ }
- drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
-
- return 0;
+ return err;
}
/**
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index 8bc83de87250..923cb074d0cb 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -134,12 +134,16 @@ int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr)
static inline
int xe_svm_init(struct xe_vm *vm)
{
- return 0;
+ return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
+ NULL, NULL, 0, 0, 0, NULL, NULL, 0);
}
static inline
void xe_svm_fini(struct xe_vm *vm)
{
+ xe_assert(vm->xe, xe_vm_is_closed(vm));
+
+ drm_gpusvm_fini(&vm->svm.gpusvm);
}
static inline
diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
index 0c69ef6b5ec5..b900afe61931 100644
--- a/drivers/gpu/drm/xe/xe_vm.c
+++ b/drivers/gpu/drm/xe/xe_vm.c
@@ -40,7 +40,6 @@
#include "xe_sync.h"
#include "xe_trace_bo.h"
#include "xe_wa.h"
-#include "xe_hmm.h"
static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
{
@@ -53,7 +52,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
*
* Check if the userptr vma has been invalidated since last successful
* repin. The check is advisory only and can the function can be called
- * without the vm->userptr.notifier_lock held. There is no guarantee that the
+ * without the vm->svm.gpusvm.notifier_lock held. There is no guarantee that the
* vma userptr will remain valid after a lockless check, so typically
* the call needs to be followed by a proper check under the notifier_lock.
*
@@ -62,7 +61,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma)
{
return mmu_interval_check_retry(&uvma->userptr.notifier,
- uvma->userptr.notifier_seq) ?
+ uvma->userptr.pages.notifier_seq) ?
-EAGAIN : 0;
}
@@ -71,11 +70,22 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
struct xe_vma *vma = &uvma->vma;
struct xe_vm *vm = xe_vma_vm(vma);
struct xe_device *xe = vm->xe;
+ struct drm_gpusvm_ctx ctx = {
+ .read_only = xe_vma_read_only(vma),
+ };
lockdep_assert_held(&vm->lock);
xe_assert(xe, xe_vma_is_userptr(vma));
- return xe_hmm_userptr_populate_range(uvma, false);
+ if (vma->gpuva.flags & XE_VMA_DESTROYED)
+ return 0;
+
+ return drm_gpusvm_get_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
+ uvma->userptr.notifier.mm,
+ &uvma->userptr.notifier,
+ xe_vma_userptr(vma),
+ xe_vma_userptr(vma) + xe_vma_size(vma),
+ &ctx);
}
static bool preempt_fences_waiting(struct xe_vm *vm)
@@ -249,7 +259,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
++vm->preempt.num_exec_queues;
q->lr.pfence = pfence;
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
drm_gpuvm_resv_add_fence(&vm->gpuvm, exec, pfence,
DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_BOOKKEEP);
@@ -263,7 +273,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
if (wait)
dma_fence_enable_sw_signaling(pfence);
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
out_fini:
drm_exec_fini(exec);
@@ -305,14 +315,14 @@ void xe_vm_remove_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
* @vm: The VM.
*
* This function checks for whether the VM has userptrs that need repinning,
- * and provides a release-type barrier on the userptr.notifier_lock after
+ * and provides a release-type barrier on the svm.gpusvm.notifier_lock after
* checking.
*
* Return: 0 if there are no userptrs needing repinning, -EAGAIN if there are.
*/
int __xe_vm_userptr_needs_repin(struct xe_vm *vm)
{
- lockdep_assert_held_read(&vm->userptr.notifier_lock);
+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
return (list_empty(&vm->userptr.repin_list) &&
list_empty(&vm->userptr.invalidated)) ? 0 : -EAGAIN;
@@ -546,9 +556,9 @@ static void preempt_rebind_work_func(struct work_struct *w)
(!(__tries)++ || __xe_vm_userptr_needs_repin(__vm)) : \
__xe_vm_userptr_needs_repin(__vm))
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
if (retry_required(tries, vm)) {
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
err = -EAGAIN;
goto out_unlock;
}
@@ -562,7 +572,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
/* Point of no return. */
arm_preempt_fences(vm, &preempt_fences);
resume_and_reinstall_preempt_fences(vm, &exec);
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
out_unlock:
drm_exec_fini(&exec);
@@ -589,6 +599,9 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv
struct xe_vma *vma = &uvma->vma;
struct dma_resv_iter cursor;
struct dma_fence *fence;
+ struct drm_gpusvm_ctx ctx = {
+ .in_notifier = true,
+ };
long err;
/*
@@ -625,7 +638,8 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv
XE_WARN_ON(err);
}
- xe_hmm_userptr_unmap(uvma);
+ drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
+ xe_vma_size(vma) >> PAGE_SHIFT, &ctx);
}
static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
@@ -646,11 +660,11 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
"NOTIFIER: addr=0x%016llx, range=0x%016llx",
xe_vma_start(vma), xe_vma_size(vma));
- down_write(&vm->userptr.notifier_lock);
+ down_write(&vm->svm.gpusvm.notifier_lock);
mmu_interval_set_seq(mni, cur_seq);
__vma_userptr_invalidate(vm, uvma);
- up_write(&vm->userptr.notifier_lock);
+ up_write(&vm->svm.gpusvm.notifier_lock);
trace_xe_vma_userptr_invalidate_complete(vma);
return true;
@@ -674,7 +688,7 @@ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
/* Protect against concurrent userptr pinning */
lockdep_assert_held(&vm->lock);
/* Protect against concurrent notifiers */
- lockdep_assert_held(&vm->userptr.notifier_lock);
+ lockdep_assert_held(&vm->svm.gpusvm.notifier_lock);
/*
* Protect against concurrent instances of this function and
* the critical exec sections
@@ -747,7 +761,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
}
if (err) {
- down_write(&vm->userptr.notifier_lock);
+ down_write(&vm->svm.gpusvm.notifier_lock);
spin_lock(&vm->userptr.invalidated_lock);
list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list,
userptr.repin_link) {
@@ -756,7 +770,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
&vm->userptr.invalidated);
}
spin_unlock(&vm->userptr.invalidated_lock);
- up_write(&vm->userptr.notifier_lock);
+ up_write(&vm->svm.gpusvm.notifier_lock);
}
return err;
}
@@ -1222,7 +1236,6 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
INIT_LIST_HEAD(&userptr->invalidate_link);
INIT_LIST_HEAD(&userptr->repin_link);
vma->gpuva.gem.offset = bo_offset_or_userptr;
- mutex_init(&userptr->unmap_mutex);
err = mmu_interval_notifier_insert(&userptr->notifier,
current->mm,
@@ -1233,7 +1246,7 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
return ERR_PTR(err);
}
- userptr->notifier_seq = LONG_MAX;
+ userptr->pages.notifier_seq = LONG_MAX;
}
xe_vm_get(vm);
@@ -1255,8 +1268,8 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
struct xe_userptr_vma *uvma = to_userptr_vma(vma);
struct xe_userptr *userptr = &uvma->userptr;
- if (userptr->sg)
- xe_hmm_userptr_free_sg(uvma);
+ drm_gpusvm_free_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
+ xe_vma_size(vma) >> PAGE_SHIFT);
/*
* Since userptr pages are not pinned, we can't remove
@@ -1264,7 +1277,6 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
* them anymore
*/
mmu_interval_notifier_remove(&userptr->notifier);
- mutex_destroy(&userptr->unmap_mutex);
xe_vm_put(vm);
} else if (xe_vma_is_null(vma) || xe_vma_is_cpu_addr_mirror(vma)) {
xe_vm_put(vm);
@@ -1657,7 +1669,6 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
INIT_LIST_HEAD(&vm->userptr.repin_list);
INIT_LIST_HEAD(&vm->userptr.invalidated);
- init_rwsem(&vm->userptr.notifier_lock);
spin_lock_init(&vm->userptr.invalidated_lock);
ttm_lru_bulk_move_init(&vm->lru_bulk_move);
@@ -1757,11 +1768,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
}
}
- if (flags & XE_VM_FLAG_FAULT_MODE) {
- err = xe_svm_init(vm);
- if (err)
- goto err_close;
- }
+ err = xe_svm_init(vm);
+ if (err)
+ goto err_close;
if (number_tiles > 1)
vm->composite_fence_ctx = dma_fence_context_alloc(1);
@@ -1867,9 +1876,9 @@ void xe_vm_close_and_put(struct xe_vm *vm)
vma = gpuva_to_vma(gpuva);
if (xe_vma_has_no_bo(vma)) {
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
vma->gpuva.flags |= XE_VMA_DESTROYED;
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
}
xe_vm_remove_vma(vm, vma);
@@ -1913,8 +1922,7 @@ void xe_vm_close_and_put(struct xe_vm *vm)
xe_vma_destroy_unlocked(vma);
}
- if (xe_vm_in_fault_mode(vm))
- xe_svm_fini(vm);
+ xe_svm_fini(vm);
up_write(&vm->lock);
@@ -2145,9 +2153,9 @@ static const u32 region_to_mem_type[] = {
static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
bool post_commit)
{
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
vma->gpuva.flags |= XE_VMA_DESTROYED;
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
if (post_commit)
xe_vm_remove_vma(vm, vma);
}
@@ -2643,9 +2651,9 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
struct xe_vma *vma = gpuva_to_vma(op->base.unmap.va);
if (vma) {
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
vma->gpuva.flags &= ~XE_VMA_DESTROYED;
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
if (post_commit)
xe_vm_insert_vma(vm, vma);
}
@@ -2664,9 +2672,9 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
xe_vma_destroy_unlocked(op->remap.next);
}
if (vma) {
- down_read(&vm->userptr.notifier_lock);
+ down_read(&vm->svm.gpusvm.notifier_lock);
vma->gpuva.flags &= ~XE_VMA_DESTROYED;
- up_read(&vm->userptr.notifier_lock);
+ up_read(&vm->svm.gpusvm.notifier_lock);
if (post_commit)
xe_vm_insert_vma(vm, vma);
}
@@ -3648,7 +3656,7 @@ int xe_vm_invalidate_vma(struct xe_vma *vma)
if (xe_vma_is_userptr(vma)) {
WARN_ON_ONCE(!mmu_interval_check_retry
(&to_userptr_vma(vma)->userptr.notifier,
- to_userptr_vma(vma)->userptr.notifier_seq));
+ to_userptr_vma(vma)->userptr.pages.notifier_seq));
WARN_ON_ONCE(!dma_resv_test_signaled(xe_vm_resv(xe_vma_vm(vma)),
DMA_RESV_USAGE_BOOKKEEP));
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index 1662604c4486..b57c4299875a 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -52,26 +52,21 @@ struct xe_userptr {
struct list_head invalidate_link;
/** @userptr: link into VM repin list if userptr. */
struct list_head repin_link;
+ /**
+ * @pages: gpusvm pages for this user pointer.
+ */
+ struct drm_gpusvm_pages pages;
/**
* @notifier: MMU notifier for user pointer (invalidation call back)
*/
struct mmu_interval_notifier notifier;
- /** @sgt: storage for a scatter gather table */
- struct sg_table sgt;
- /** @sg: allocated scatter gather table */
- struct sg_table *sg;
- /** @notifier_seq: notifier sequence number */
- unsigned long notifier_seq;
- /** @unmap_mutex: Mutex protecting dma-unmapping */
- struct mutex unmap_mutex;
+
/**
* @initial_bind: user pointer has been bound at least once.
- * write: vm->userptr.notifier_lock in read mode and vm->resv held.
- * read: vm->userptr.notifier_lock in write mode or vm->resv held.
+ * write: vm->svm.gpusvm.notifier_lock in read mode and vm->resv held.
+ * read: vm->svm.gpusvm.notifier_lock in write mode or vm->resv held.
*/
bool initial_bind;
- /** @mapped: Whether the @sgt sg-table is dma-mapped. Protected by @unmap_mutex. */
- bool mapped;
#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT)
u32 divisor;
#endif
@@ -109,7 +104,7 @@ struct xe_vma {
/**
* @tile_present: GT mask of binding are present for this VMA.
* protected by vm->lock, vm->resv and for userptrs,
- * vm->userptr.notifier_lock for writing. Needs either for reading,
+ * vm->svm.gpusvm.notifier_lock for writing. Needs either for reading,
* but if reading is done under the vm->lock only, it needs to be held
* in write mode.
*/
@@ -243,11 +238,6 @@ struct xe_vm {
* and needs repinning. Protected by @lock.
*/
struct list_head repin_list;
- /**
- * @notifier_lock: protects notifier in write mode and
- * submission in read mode.
- */
- struct rw_semaphore notifier_lock;
/**
* @userptr.invalidated_lock: Protects the
* @userptr.invalidated list.
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
` (5 preceding siblings ...)
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
@ 2025-04-24 12:18 ` Matthew Auld
2025-04-24 15:43 ` kernel test robot
2025-04-24 23:18 ` Matthew Brost
6 siblings, 2 replies; 18+ messages in thread
From: Matthew Auld @ 2025-04-24 12:18 UTC (permalink / raw)
To: intel-xe
Cc: dri-devel, Matthew Brost, Himal Prasad Ghimiray,
Thomas Hellström
We now use the same notifier lock for SVM and userptr, with that we can
combine xe_pt_userptr_pre_commit and xe_pt_svm_pre_commit.
v2: (Matt B)
- Re-use xe_svm_notifier_lock/unlock for userptr.
- Combine svm/userptr handling further down into op_check_svm_userptr.
Suggested-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/gpu/drm/xe/xe_pt.c | 90 ++++++++++----------------------
drivers/gpu/drm/xe/xe_pt_types.h | 2 -
drivers/gpu/drm/xe/xe_svm.h | 19 +++----
3 files changed, 39 insertions(+), 72 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index ff898e518afd..a7db65f9913e 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -1393,8 +1393,8 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
return 0;
}
-static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
- struct xe_vm_pgtable_update_ops *pt_update)
+static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op,
+ struct xe_vm_pgtable_update_ops *pt_update)
{
int err = 0;
@@ -1419,6 +1419,24 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va),
pt_update);
break;
+#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
+ case DRM_GPUVA_OP_DRIVER:
+ if (op->subop == XE_VMA_SUBOP_MAP_RANGE) {
+ struct xe_svm_range *range = op->map_range.range;
+
+ xe_svm_range_debug(range, "PRE-COMMIT");
+
+ xe_assert(vm->xe,
+ xe_vma_is_cpu_addr_mirror(op->map_range.vma));
+ xe_assert(vm->xe, op->subop == XE_VMA_SUBOP_MAP_RANGE);
+
+ if (!xe_svm_range_pages_valid(range)) {
+ xe_svm_range_debug(range, "PRE-COMMIT - RETRY");
+ err = -EAGAIN;
+ }
+ }
+ break;
+#endif
default:
drm_warn(&vm->xe->drm, "NOT POSSIBLE");
}
@@ -1426,7 +1444,7 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
return err;
}
-static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
+static int xe_pt_svm_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
{
struct xe_vm *vm = pt_update->vops->vm;
struct xe_vma_ops *vops = pt_update->vops;
@@ -1439,12 +1457,12 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
if (err)
return err;
- down_read(&vm->svm.gpusvm.notifier_lock);
+ xe_svm_notifier_lock(vm);
list_for_each_entry(op, &vops->list, link) {
- err = op_check_userptr(vm, op, pt_update_ops);
+ err = op_check_svm_userptr(vm, op, pt_update_ops);
if (err) {
- up_read(&vm->svm.gpusvm.notifier_lock);
+ xe_svm_notifier_unlock(vm);
break;
}
}
@@ -1452,42 +1470,6 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
return err;
}
-#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
-static int xe_pt_svm_pre_commit(struct xe_migrate_pt_update *pt_update)
-{
- struct xe_vm *vm = pt_update->vops->vm;
- struct xe_vma_ops *vops = pt_update->vops;
- struct xe_vma_op *op;
- int err;
-
- err = xe_pt_pre_commit(pt_update);
- if (err)
- return err;
-
- xe_svm_notifier_lock(vm);
-
- list_for_each_entry(op, &vops->list, link) {
- struct xe_svm_range *range = op->map_range.range;
-
- if (op->subop == XE_VMA_SUBOP_UNMAP_RANGE)
- continue;
-
- xe_svm_range_debug(range, "PRE-COMMIT");
-
- xe_assert(vm->xe, xe_vma_is_cpu_addr_mirror(op->map_range.vma));
- xe_assert(vm->xe, op->subop == XE_VMA_SUBOP_MAP_RANGE);
-
- if (!xe_svm_range_pages_valid(range)) {
- xe_svm_range_debug(range, "PRE-COMMIT - RETRY");
- xe_svm_notifier_unlock(vm);
- return -EAGAIN;
- }
- }
-
- return 0;
-}
-#endif
-
struct invalidation_fence {
struct xe_gt_tlb_invalidation_fence base;
struct xe_gt *gt;
@@ -1858,7 +1840,7 @@ static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile,
xe_vma_start(vma),
xe_vma_end(vma));
++pt_update_ops->current_op;
- pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma);
+ pt_update_ops->needs_svm_lock |= xe_vma_is_userptr(vma);
/*
* If rebind, we have to invalidate TLB on !LR vms to invalidate
@@ -1966,7 +1948,7 @@ static int unbind_op_prepare(struct xe_tile *tile,
xe_pt_update_ops_rfence_interval(pt_update_ops, xe_vma_start(vma),
xe_vma_end(vma));
++pt_update_ops->current_op;
- pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma);
+ pt_update_ops->needs_svm_lock |= xe_vma_is_userptr(vma);
pt_update_ops->needs_invalidation = true;
xe_pt_commit_prepare_unbind(vma, pt_op->entries, pt_op->num_entries);
@@ -2289,22 +2271,12 @@ static const struct xe_migrate_pt_update_ops migrate_ops = {
.pre_commit = xe_pt_pre_commit,
};
-static const struct xe_migrate_pt_update_ops userptr_migrate_ops = {
+static const struct xe_migrate_pt_update_ops svm_userptr_migrate_ops = {
.populate = xe_vm_populate_pgtable,
.clear = xe_migrate_clear_pgtable_callback,
- .pre_commit = xe_pt_userptr_pre_commit,
+ .pre_commit = xe_pt_svm_userptr_pre_commit,
};
-#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
-static const struct xe_migrate_pt_update_ops svm_migrate_ops = {
- .populate = xe_vm_populate_pgtable,
- .clear = xe_migrate_clear_pgtable_callback,
- .pre_commit = xe_pt_svm_pre_commit,
-};
-#else
-static const struct xe_migrate_pt_update_ops svm_migrate_ops;
-#endif
-
/**
* xe_pt_update_ops_run() - Run PT update operations
* @tile: Tile of PT update operations
@@ -2331,9 +2303,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
int err = 0, i;
struct xe_migrate_pt_update update = {
.ops = pt_update_ops->needs_svm_lock ?
- &svm_migrate_ops :
- pt_update_ops->needs_userptr_lock ?
- &userptr_migrate_ops :
+ &svm_userptr_migrate_ops :
&migrate_ops,
.vops = vops,
.tile_id = tile->id,
@@ -2455,8 +2425,6 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
if (pt_update_ops->needs_svm_lock)
xe_svm_notifier_unlock(vm);
- if (pt_update_ops->needs_userptr_lock)
- up_read(&vm->svm.gpusvm.notifier_lock);
return fence;
diff --git a/drivers/gpu/drm/xe/xe_pt_types.h b/drivers/gpu/drm/xe/xe_pt_types.h
index 69eab6f37cfe..dc0b2d8c3af8 100644
--- a/drivers/gpu/drm/xe/xe_pt_types.h
+++ b/drivers/gpu/drm/xe/xe_pt_types.h
@@ -106,8 +106,6 @@ struct xe_vm_pgtable_update_ops {
u32 current_op;
/** @needs_svm_lock: Needs SVM lock */
bool needs_svm_lock;
- /** @needs_userptr_lock: Needs userptr lock */
- bool needs_userptr_lock;
/** @needs_invalidation: Needs invalidation */
bool needs_invalidation;
/**
diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
index 923cb074d0cb..696496b52465 100644
--- a/drivers/gpu/drm/xe/xe_svm.h
+++ b/drivers/gpu/drm/xe/xe_svm.h
@@ -87,15 +87,6 @@ static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range)
return range->base.pages.flags.has_dma_mapping;
}
-#define xe_svm_assert_in_notifier(vm__) \
- lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock)
-
-#define xe_svm_notifier_lock(vm__) \
- drm_gpusvm_notifier_lock(&(vm__)->svm.gpusvm)
-
-#define xe_svm_notifier_unlock(vm__) \
- drm_gpusvm_notifier_unlock(&(vm__)->svm.gpusvm)
-
#else
#include <linux/interval_tree.h>
@@ -187,4 +178,14 @@ static inline void xe_svm_notifier_unlock(struct xe_vm *vm)
{
}
#endif
+
+#define xe_svm_assert_in_notifier(vm__) \
+ lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock)
+
+#define xe_svm_notifier_lock(vm__) \
+ drm_gpusvm_notifier_lock(&(vm__)->svm.gpusvm)
+
+#define xe_svm_notifier_unlock(vm__) \
+ drm_gpusvm_notifier_unlock(&(vm__)->svm.gpusvm)
+
#endif
--
2.49.0
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
@ 2025-04-24 14:21 ` kernel test robot
2025-04-24 14:42 ` kernel test robot
` (3 subsequent siblings)
4 siblings, 0 replies; 18+ messages in thread
From: kernel test robot @ 2025-04-24 14:21 UTC (permalink / raw)
To: Matthew Auld, intel-xe
Cc: oe-kbuild-all, dri-devel, Himal Prasad Ghimiray,
Thomas Hellström, Matthew Brost
Hi Matthew,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-xe/drm-xe-next]
[also build test ERROR on next-20250424]
[cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128
base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next
patch link: https://lore.kernel.org/r/20250424121827.862729-15-matthew.auld%40intel.com
patch subject: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
config: csky-randconfig-001-20250424 (https://download.01.org/0day-ci/archive/20250424/202504242229.drmSYxrH-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 12.4.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250424/202504242229.drmSYxrH-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504242229.drmSYxrH-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/gpu/drm/drm_gpusvm.c: In function 'drm_gpusvm_get_devmem_page':
>> drivers/gpu/drm/drm_gpusvm.c:1709:9: error: implicit declaration of function 'zone_device_page_init' [-Werror=implicit-function-declaration]
1709 | zone_device_page_init(page);
| ^~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
--
In file included from drivers/gpu/drm/xe/xe_tile.c:16:
drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_init':
>> drivers/gpu/drm/xe/xe_svm.h:137:16: error: implicit declaration of function 'drm_gpusvm_init'; did you mean 'drm_mm_init'? [-Werror=implicit-function-declaration]
137 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
| ^~~~~~~~~~~~~~~
| drm_mm_init
>> drivers/gpu/drm/xe/xe_svm.h:137:35: error: invalid use of undefined type 'struct xe_vm'
137 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
| ^~
drivers/gpu/drm/xe/xe_svm.h:137:71: error: invalid use of undefined type 'struct xe_vm'
137 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
| ^~
In file included from drivers/gpu/drm/xe/xe_sriov.h:9,
from drivers/gpu/drm/xe/xe_device.h:13,
from drivers/gpu/drm/xe/xe_tile.c:10:
drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_fini':
drivers/gpu/drm/xe/xe_svm.h:144:21: error: invalid use of undefined type 'struct xe_vm'
144 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~
drivers/gpu/drm/xe/xe_assert.h:110:41: note: in definition of macro 'xe_assert_msg'
110 | const struct xe_device *__xe = (xe); \
| ^~
drivers/gpu/drm/xe/xe_svm.h:144:9: note: in expansion of macro 'xe_assert'
144 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~~~~~~~~
In file included from include/linux/bits.h:22,
from include/linux/gfp_types.h:5,
from include/linux/gfp.h:5,
from include/drm/drm_managed.h:6,
from drivers/gpu/drm/xe/xe_tile.c:8:
>> drivers/gpu/drm/xe/xe_svm.h:144:27: error: implicit declaration of function 'xe_vm_is_closed' [-Werror=implicit-function-declaration]
144 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~~~~~~~~~~~~~~
include/linux/build_bug.h:30:63: note: in definition of macro 'BUILD_BUG_ON_INVALID'
30 | #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e))))
| ^
drivers/gpu/drm/xe/xe_assert.h:111:9: note: in expansion of macro '__xe_assert_msg'
111 | __xe_assert_msg(__xe, condition, \
| ^~~~~~~~~~~~~~~
drivers/gpu/drm/xe/xe_assert.h:108:34: note: in expansion of macro 'xe_assert_msg'
108 | #define xe_assert(xe, condition) xe_assert_msg((xe), condition, "")
| ^~~~~~~~~~~~~
drivers/gpu/drm/xe/xe_svm.h:144:9: note: in expansion of macro 'xe_assert'
144 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~~~~~~~~
>> drivers/gpu/drm/xe/xe_svm.h:146:9: error: implicit declaration of function 'drm_gpusvm_fini'; did you mean 'drm_buddy_fini'? [-Werror=implicit-function-declaration]
146 | drm_gpusvm_fini(&vm->svm.gpusvm);
| ^~~~~~~~~~~~~~~
| drm_buddy_fini
drivers/gpu/drm/xe/xe_svm.h:146:28: error: invalid use of undefined type 'struct xe_vm'
146 | drm_gpusvm_fini(&vm->svm.gpusvm);
| ^~
cc1: some warnings being treated as errors
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for DRM_GPUSVM
Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DEVICE_PRIVATE [=n]
Selected by [m]:
- DRM_XE [=m] && HAS_IOMEM [=y] && DRM [=y] && PCI [=y] && MMU [=y] && (m [=m] && MODULES [=y] || KUNIT [=n]=y [=y])
vim +137 drivers/gpu/drm/xe/xe_svm.h
133
134 static inline
135 int xe_svm_init(struct xe_vm *vm)
136 {
> 137 return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
138 NULL, NULL, 0, 0, 0, NULL, NULL, 0);
139 }
140
141 static inline
142 void xe_svm_fini(struct xe_vm *vm)
143 {
> 144 xe_assert(vm->xe, xe_vm_is_closed(vm));
145
> 146 drm_gpusvm_fini(&vm->svm.gpusvm);
147 }
148
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
2025-04-24 14:21 ` kernel test robot
@ 2025-04-24 14:42 ` kernel test robot
2025-04-24 23:17 ` Matthew Brost
` (2 subsequent siblings)
4 siblings, 0 replies; 18+ messages in thread
From: kernel test robot @ 2025-04-24 14:42 UTC (permalink / raw)
To: Matthew Auld, intel-xe
Cc: oe-kbuild-all, dri-devel, Himal Prasad Ghimiray,
Thomas Hellström, Matthew Brost
Hi Matthew,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-xe/drm-xe-next]
[also build test ERROR on next-20250424]
[cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128
base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next
patch link: https://lore.kernel.org/r/20250424121827.862729-15-matthew.auld%40intel.com
patch subject: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
config: loongarch-randconfig-002-20250424 (https://download.01.org/0day-ci/archive/20250424/202504242203.MfhcD5LA-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 12.4.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250424/202504242203.MfhcD5LA-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504242203.MfhcD5LA-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from include/linux/irqflags.h:19,
from include/linux/spinlock.h:59,
from include/linux/sched.h:2213,
from include/linux/ratelimit.h:6,
from include/linux/dev_printk.h:16,
from include/linux/device.h:15,
from include/drm/drm_print.h:31,
from drivers/gpu/drm/xe/xe_assert.h:11,
from drivers/gpu/drm/xe/xe_vm.h:9,
from drivers/gpu/drm/xe/xe_vm.c:6:
arch/loongarch/include/asm/percpu.h:20:4: error: #error compiler support for the model attribute is necessary when a recent assembler is used
20 | # error compiler support for the model attribute is necessary when a recent assembler is used
| ^~~~~
drivers/gpu/drm/xe/xe_vm.c: In function 'xe_vma_userptr_force_invalidate':
>> drivers/gpu/drm/xe/xe_vm.c:699:52: error: 'struct xe_userptr' has no member named 'notifier_seq'; did you mean 'notifier'?
699 | uvma->userptr.notifier_seq))
| ^~~~~~~~~~~~
| notifier
drivers/gpu/drm/xe/xe_vm.c:700:31: error: 'struct xe_userptr' has no member named 'notifier_seq'; did you mean 'notifier'?
700 | uvma->userptr.notifier_seq -= 2;
| ^~~~~~~~~~~~
| notifier
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for DRM_GPUSVM
Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DEVICE_PRIVATE [=n]
Selected by [m]:
- DRM_XE [=m] && HAS_IOMEM [=y] && DRM [=y] && PCI [=y] && MMU [=y] && (m [=m] && MODULES [=y] || KUNIT [=n]=y [=y])
vim +699 drivers/gpu/drm/xe/xe_vm.c
dd08ebf6c3525a Matthew Brost 2023-03-30 676
100a5b8dadfca5 Thomas Hellström 2025-02-28 677 #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT)
100a5b8dadfca5 Thomas Hellström 2025-02-28 678 /**
100a5b8dadfca5 Thomas Hellström 2025-02-28 679 * xe_vma_userptr_force_invalidate() - force invalidate a userptr
100a5b8dadfca5 Thomas Hellström 2025-02-28 680 * @uvma: The userptr vma to invalidate
100a5b8dadfca5 Thomas Hellström 2025-02-28 681 *
100a5b8dadfca5 Thomas Hellström 2025-02-28 682 * Perform a forced userptr invalidation for testing purposes.
100a5b8dadfca5 Thomas Hellström 2025-02-28 683 */
100a5b8dadfca5 Thomas Hellström 2025-02-28 684 void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
100a5b8dadfca5 Thomas Hellström 2025-02-28 685 {
100a5b8dadfca5 Thomas Hellström 2025-02-28 686 struct xe_vm *vm = xe_vma_vm(&uvma->vma);
100a5b8dadfca5 Thomas Hellström 2025-02-28 687
100a5b8dadfca5 Thomas Hellström 2025-02-28 688 /* Protect against concurrent userptr pinning */
100a5b8dadfca5 Thomas Hellström 2025-02-28 689 lockdep_assert_held(&vm->lock);
100a5b8dadfca5 Thomas Hellström 2025-02-28 690 /* Protect against concurrent notifiers */
a2cfe1a4a9e967 Matthew Auld 2025-04-24 691 lockdep_assert_held(&vm->svm.gpusvm.notifier_lock);
100a5b8dadfca5 Thomas Hellström 2025-02-28 692 /*
100a5b8dadfca5 Thomas Hellström 2025-02-28 693 * Protect against concurrent instances of this function and
100a5b8dadfca5 Thomas Hellström 2025-02-28 694 * the critical exec sections
100a5b8dadfca5 Thomas Hellström 2025-02-28 695 */
100a5b8dadfca5 Thomas Hellström 2025-02-28 696 xe_vm_assert_held(vm);
100a5b8dadfca5 Thomas Hellström 2025-02-28 697
100a5b8dadfca5 Thomas Hellström 2025-02-28 698 if (!mmu_interval_read_retry(&uvma->userptr.notifier,
100a5b8dadfca5 Thomas Hellström 2025-02-28 @699 uvma->userptr.notifier_seq))
100a5b8dadfca5 Thomas Hellström 2025-02-28 700 uvma->userptr.notifier_seq -= 2;
100a5b8dadfca5 Thomas Hellström 2025-02-28 701 __vma_userptr_invalidate(vm, uvma);
100a5b8dadfca5 Thomas Hellström 2025-02-28 702 }
100a5b8dadfca5 Thomas Hellström 2025-02-28 703 #endif
100a5b8dadfca5 Thomas Hellström 2025-02-28 704
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr
2025-04-24 12:18 ` [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr Matthew Auld
@ 2025-04-24 15:43 ` kernel test robot
2025-04-24 23:18 ` Matthew Brost
1 sibling, 0 replies; 18+ messages in thread
From: kernel test robot @ 2025-04-24 15:43 UTC (permalink / raw)
To: Matthew Auld, intel-xe
Cc: oe-kbuild-all, dri-devel, Matthew Brost, Himal Prasad Ghimiray,
Thomas Hellström
Hi Matthew,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-xe/drm-xe-next]
[also build test WARNING on next-20250424]
[cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128
base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next
patch link: https://lore.kernel.org/r/20250424121827.862729-16-matthew.auld%40intel.com
patch subject: [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr
config: csky-randconfig-001-20250424 (https://download.01.org/0day-ci/archive/20250424/202504242339.WQvU1OVP-lkp@intel.com/config)
compiler: csky-linux-gcc (GCC) 12.4.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250424/202504242339.WQvU1OVP-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504242339.WQvU1OVP-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/gpu/drm/xe/xe_res_cursor.h:38,
from drivers/gpu/drm/xe/xe_vm.c:38:
>> drivers/gpu/drm/xe/xe_svm.h:182: warning: "xe_svm_assert_in_notifier" redefined
182 | #define xe_svm_assert_in_notifier(vm__) \
|
drivers/gpu/drm/xe/xe_svm.h:170: note: this is the location of the previous definition
170 | #define xe_svm_assert_in_notifier(...) do {} while (0)
|
--
In file included from drivers/gpu/drm/xe/xe_tile.c:16:
drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_init':
drivers/gpu/drm/xe/xe_svm.h:128:16: error: implicit declaration of function 'drm_gpusvm_init'; did you mean 'drm_mm_init'? [-Werror=implicit-function-declaration]
128 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
| ^~~~~~~~~~~~~~~
| drm_mm_init
drivers/gpu/drm/xe/xe_svm.h:128:35: error: invalid use of undefined type 'struct xe_vm'
128 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
| ^~
drivers/gpu/drm/xe/xe_svm.h:128:71: error: invalid use of undefined type 'struct xe_vm'
128 | return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
| ^~
In file included from drivers/gpu/drm/xe/xe_sriov.h:9,
from drivers/gpu/drm/xe/xe_device.h:13,
from drivers/gpu/drm/xe/xe_tile.c:10:
drivers/gpu/drm/xe/xe_svm.h: In function 'xe_svm_fini':
drivers/gpu/drm/xe/xe_svm.h:135:21: error: invalid use of undefined type 'struct xe_vm'
135 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~
drivers/gpu/drm/xe/xe_assert.h:110:41: note: in definition of macro 'xe_assert_msg'
110 | const struct xe_device *__xe = (xe); \
| ^~
drivers/gpu/drm/xe/xe_svm.h:135:9: note: in expansion of macro 'xe_assert'
135 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~~~~~~~~
In file included from include/linux/bits.h:22,
from include/linux/gfp_types.h:5,
from include/linux/gfp.h:5,
from include/drm/drm_managed.h:6,
from drivers/gpu/drm/xe/xe_tile.c:8:
drivers/gpu/drm/xe/xe_svm.h:135:27: error: implicit declaration of function 'xe_vm_is_closed' [-Werror=implicit-function-declaration]
135 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~~~~~~~~~~~~~~
include/linux/build_bug.h:30:63: note: in definition of macro 'BUILD_BUG_ON_INVALID'
30 | #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e))))
| ^
drivers/gpu/drm/xe/xe_assert.h:111:9: note: in expansion of macro '__xe_assert_msg'
111 | __xe_assert_msg(__xe, condition, \
| ^~~~~~~~~~~~~~~
drivers/gpu/drm/xe/xe_assert.h:108:34: note: in expansion of macro 'xe_assert_msg'
108 | #define xe_assert(xe, condition) xe_assert_msg((xe), condition, "")
| ^~~~~~~~~~~~~
drivers/gpu/drm/xe/xe_svm.h:135:9: note: in expansion of macro 'xe_assert'
135 | xe_assert(vm->xe, xe_vm_is_closed(vm));
| ^~~~~~~~~
drivers/gpu/drm/xe/xe_svm.h:137:9: error: implicit declaration of function 'drm_gpusvm_fini'; did you mean 'drm_buddy_fini'? [-Werror=implicit-function-declaration]
137 | drm_gpusvm_fini(&vm->svm.gpusvm);
| ^~~~~~~~~~~~~~~
| drm_buddy_fini
drivers/gpu/drm/xe/xe_svm.h:137:28: error: invalid use of undefined type 'struct xe_vm'
137 | drm_gpusvm_fini(&vm->svm.gpusvm);
| ^~
drivers/gpu/drm/xe/xe_svm.h: At top level:
>> drivers/gpu/drm/xe/xe_svm.h:182: warning: "xe_svm_assert_in_notifier" redefined
182 | #define xe_svm_assert_in_notifier(vm__) \
|
drivers/gpu/drm/xe/xe_svm.h:170: note: this is the location of the previous definition
170 | #define xe_svm_assert_in_notifier(...) do {} while (0)
|
cc1: some warnings being treated as errors
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for DRM_GPUSVM
Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DEVICE_PRIVATE [=n]
Selected by [m]:
- DRM_XE [=m] && HAS_IOMEM [=y] && DRM [=y] && PCI [=y] && MMU [=y] && (m [=m] && MODULES [=y] || KUNIT [=n]=y [=y])
vim +/xe_svm_assert_in_notifier +182 drivers/gpu/drm/xe/xe_svm.h
181
> 182 #define xe_svm_assert_in_notifier(vm__) \
183 lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock)
184
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct
2025-04-24 12:18 ` [PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct Matthew Auld
@ 2025-04-24 21:47 ` Matthew Brost
0 siblings, 0 replies; 18+ messages in thread
From: Matthew Brost @ 2025-04-24 21:47 UTC (permalink / raw)
To: Matthew Auld; +Cc: intel-xe, dri-devel, Thomas Hellström
On Thu, Apr 24, 2025 at 01:18:32PM +0100, Matthew Auld wrote:
> Refactor the core API of get/unmap/free pages to all operate on
> drm_gpusvm_pages. In the next patch we want to export a simplified core
> API without needing fully blown svm range etc.
>
> Suggested-by: Matthew Brost <matthew.brost@intel.com>
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
> drivers/gpu/drm/drm_gpusvm.c | 161 ++++++++++++++++++++++++-----------
> 1 file changed, 110 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
> index ef38017d2159..fbe0d70ef163 100644
> --- a/drivers/gpu/drm/drm_gpusvm.c
> +++ b/drivers/gpu/drm/drm_gpusvm.c
> @@ -1128,19 +1128,19 @@ drm_gpusvm_range_find_or_insert(struct drm_gpusvm *gpusvm,
> EXPORT_SYMBOL_GPL(drm_gpusvm_range_find_or_insert);
>
> /**
> - * __drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range (internal)
> + * __drm_gpusvm_unmap_pages() - Unmap pages associated with GPU SVM pages
> + * (internal)
> * @gpusvm: Pointer to the GPU SVM structure
> - * @range: Pointer to the GPU SVM range structure
> + * @pages: Pointer to the GPU SVM pages structure
> * @npages: Number of pages to unmap
> *
> - * This function unmap pages associated with a GPU SVM range. Assumes and
> + * This function unmap pages associated with a GPU SVM pages struct. Assumes and
> * asserts correct locking is in place when called.
> */
> -static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
> - struct drm_gpusvm_range *range,
> - unsigned long npages)
> +static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + unsigned long npages)
> {
> - struct drm_gpusvm_pages *svm_pages = &range->pages;
> struct drm_pagemap *dpagemap = svm_pages->dpagemap;
> struct device *dev = gpusvm->drm->dev;
> unsigned long i, j;
> @@ -1168,17 +1168,15 @@ static void __drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
> }
>
> /**
> - * drm_gpusvm_range_free_pages() - Free pages associated with a GPU SVM range
> + * __drm_gpusvm_free_pages() - Free dma array associated with GPU SVM pages
> * @gpusvm: Pointer to the GPU SVM structure
> - * @range: Pointer to the GPU SVM range structure
> + * @svm_pages: Pointer to the GPU SVM pages structure
> *
> * This function frees the dma address array associated with a GPU SVM range.
> */
> -static void drm_gpusvm_range_free_pages(struct drm_gpusvm *gpusvm,
> - struct drm_gpusvm_range *range)
> +static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages)
> {
> - struct drm_gpusvm_pages *svm_pages = &range->pages;
> -
> lockdep_assert_held(&gpusvm->notifier_lock);
>
> if (svm_pages->dma_addr) {
> @@ -1211,8 +1209,8 @@ void drm_gpusvm_range_remove(struct drm_gpusvm *gpusvm,
> return;
>
> drm_gpusvm_notifier_lock(gpusvm);
> - __drm_gpusvm_range_unmap_pages(gpusvm, range, npages);
> - drm_gpusvm_range_free_pages(gpusvm, range);
> + __drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages);
> + __drm_gpusvm_free_pages(gpusvm, &range->pages);
> __drm_gpusvm_range_remove(notifier, range);
> drm_gpusvm_notifier_unlock(gpusvm);
>
> @@ -1277,6 +1275,28 @@ void drm_gpusvm_range_put(struct drm_gpusvm_range *range)
> }
> EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
>
> +/**
> + * drm_gpusvm_pages_valid() - GPU SVM range pages valid
> + * @gpusvm: Pointer to the GPU SVM structure
> + * @svm_pages: Pointer to the GPU SVM pages structure
> + *
> + * This function determines if a GPU SVM range pages are valid. Expected be
> + * called holding gpusvm->notifier_lock and as the last step before committing a
> + * GPU binding. This is akin to a notifier seqno check in the HMM documentation
> + * but due to wider notifiers (i.e., notifiers which span multiple ranges) this
> + * function is required for finer grained checking (i.e., per range) if pages
> + * are valid.
> + *
> + * Return: True if GPU SVM range has valid pages, False otherwise
> + */
> +static bool drm_gpusvm_pages_valid(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages)
> +{
> + lockdep_assert_held(&gpusvm->notifier_lock);
> +
> + return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
> +}
> +
> /**
> * drm_gpusvm_range_pages_valid() - GPU SVM range pages valid
> * @gpusvm: Pointer to the GPU SVM structure
> @@ -1294,11 +1314,7 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_put);
> bool drm_gpusvm_range_pages_valid(struct drm_gpusvm *gpusvm,
> struct drm_gpusvm_range *range)
> {
> - struct drm_gpusvm_pages *svm_pages = &range->pages;
> -
> - lockdep_assert_held(&gpusvm->notifier_lock);
> -
> - return svm_pages->flags.has_devmem_pages || svm_pages->flags.has_dma_mapping;
> + return drm_gpusvm_pages_valid(gpusvm, &range->pages);
> }
> EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
>
> @@ -1312,57 +1328,59 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_pages_valid);
> *
> * Return: True if GPU SVM range has valid pages, False otherwise
> */
> -static bool
> -drm_gpusvm_range_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
> - struct drm_gpusvm_range *range)
I think the kernel doc needs to be updated here.
Other that this nit, patch LGTM:
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
> +static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages)
> {
> - struct drm_gpusvm_pages *svm_pages = &range->pages;
> bool pages_valid;
>
> if (!svm_pages->dma_addr)
> return false;
>
> drm_gpusvm_notifier_lock(gpusvm);
> - pages_valid = drm_gpusvm_range_pages_valid(gpusvm, range);
> + pages_valid = drm_gpusvm_pages_valid(gpusvm, svm_pages);
> if (!pages_valid)
> - drm_gpusvm_range_free_pages(gpusvm, range);
> + __drm_gpusvm_free_pages(gpusvm, svm_pages);
> drm_gpusvm_notifier_unlock(gpusvm);
>
> return pages_valid;
> }
>
> /**
> - * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
> + * drm_gpusvm_get_pages() - Get pages and populate GPU SVM pages struct
> * @gpusvm: Pointer to the GPU SVM structure
> - * @range: Pointer to the GPU SVM range structure
> + * @svm_pages: The SVM pages to populate. This will contain the dma-addresses
> + * @mm: The mm corresponding to the CPU range
> + * @notifier: The corresponding notifier for the given CPU range
> + * @pages_start: Start CPU address for the pages
> + * @pages_end: End CPU address for the pages (exclusive)
> * @ctx: GPU SVM context
> *
> - * This function gets pages for a GPU SVM range and ensures they are mapped for
> - * DMA access.
> + * This function gets and maps pages for CPU range and ensures they are
> + * mapped for DMA access.
> *
> * Return: 0 on success, negative error code on failure.
> */
> -int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
> - struct drm_gpusvm_range *range,
> - const struct drm_gpusvm_ctx *ctx)
> +static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + struct mm_struct *mm,
> + struct mmu_interval_notifier *notifier,
> + unsigned long pages_start,
> + unsigned long pages_end,
> + const struct drm_gpusvm_ctx *ctx)
> {
> - struct drm_gpusvm_pages *svm_pages = &range->pages;
> - struct mmu_interval_notifier *notifier = &range->notifier->notifier;
> struct hmm_range hmm_range = {
> .default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
> HMM_PFN_REQ_WRITE),
> .notifier = notifier,
> - .start = drm_gpusvm_range_start(range),
> - .end = drm_gpusvm_range_end(range),
> + .start = pages_start,
> + .end = pages_end,
> .dev_private_owner = gpusvm->device_private_page_owner,
> };
> - struct mm_struct *mm = gpusvm->mm;
> struct drm_gpusvm_zdd *zdd;
> unsigned long timeout =
> jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
> unsigned long i, j;
> - unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
> - drm_gpusvm_range_end(range));
> + unsigned long npages = npages_in_range(pages_start, pages_end);
> unsigned long num_dma_mapped;
> unsigned int order = 0;
> unsigned long *pfns;
> @@ -1375,7 +1393,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
>
> retry:
> hmm_range.notifier_seq = mmu_interval_read_begin(notifier);
> - if (drm_gpusvm_range_pages_valid_unlocked(gpusvm, range))
> + if (drm_gpusvm_pages_valid_unlocked(gpusvm, svm_pages))
> goto set_seqno;
>
> pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
> @@ -1522,7 +1540,7 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
> return 0;
>
> err_unmap:
> - __drm_gpusvm_range_unmap_pages(gpusvm, range, num_dma_mapped);
> + __drm_gpusvm_unmap_pages(gpusvm, svm_pages, num_dma_mapped);
> drm_gpusvm_notifier_unlock(gpusvm);
> err_free:
> kvfree(pfns);
> @@ -1530,8 +1548,57 @@ int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
> goto retry;
> return err;
> }
> +
> +/**
> + * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
> + * @gpusvm: Pointer to the GPU SVM structure
> + * @range: Pointer to the GPU SVM range structure
> + * @ctx: GPU SVM context
> + *
> + * This function gets pages for a GPU SVM range and ensures they are mapped for
> + * DMA access.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +int drm_gpusvm_range_get_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_range *range,
> + const struct drm_gpusvm_ctx *ctx)
> +{
> + return drm_gpusvm_get_pages(gpusvm, &range->pages, gpusvm->mm,
> + &range->notifier->notifier,
> + drm_gpusvm_range_start(range),
> + drm_gpusvm_range_end(range), ctx);
> +}
> EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
>
> +/**
> + * drm_gpusvm_unmap_pages() - Unmap GPU svm pages
> + * @gpusvm: Pointer to the GPU SVM structure
> + * @pages: Pointer to the GPU SVM pages structure
> + * @ctx: GPU SVM context
> + *
> + * This function unmaps pages associated with a GPU SVM pages struct. If
> + * @in_notifier is set, it is assumed that gpusvm->notifier_lock is held in
> + * write mode; if it is clear, it acquires gpusvm->notifier_lock in read mode.
> + * Must be called in the invalidate() callback of the corresponding notifier for
> + * IOMMU security model.
> + */
> +static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + unsigned long npages,
> + const struct drm_gpusvm_ctx *ctx)
> +{
> + if (ctx->in_notifier)
> + lockdep_assert_held_write(&gpusvm->notifier_lock);
> + else
> + drm_gpusvm_notifier_lock(gpusvm);
> +
> + __drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages);
> +
> + if (!ctx->in_notifier)
> + drm_gpusvm_notifier_unlock(gpusvm);
> +}
> +
> /**
> * drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
> * @gpusvm: Pointer to the GPU SVM structure
> @@ -1551,15 +1618,7 @@ void drm_gpusvm_range_unmap_pages(struct drm_gpusvm *gpusvm,
> unsigned long npages = npages_in_range(drm_gpusvm_range_start(range),
> drm_gpusvm_range_end(range));
>
> - if (ctx->in_notifier)
> - lockdep_assert_held_write(&gpusvm->notifier_lock);
> - else
> - drm_gpusvm_notifier_lock(gpusvm);
> -
> - __drm_gpusvm_range_unmap_pages(gpusvm, range, npages);
> -
> - if (!ctx->in_notifier)
> - drm_gpusvm_notifier_unlock(gpusvm);
> + return drm_gpusvm_unmap_pages(gpusvm, &range->pages, npages, ctx);
> }
> EXPORT_SYMBOL_GPL(drm_gpusvm_range_unmap_pages);
>
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API
2025-04-24 12:18 ` [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API Matthew Auld
@ 2025-04-24 22:01 ` Matthew Brost
2025-04-24 22:04 ` Matthew Brost
0 siblings, 1 reply; 18+ messages in thread
From: Matthew Brost @ 2025-04-24 22:01 UTC (permalink / raw)
To: Matthew Auld; +Cc: intel-xe, dri-devel, Thomas Hellström
On Thu, Apr 24, 2025 at 01:18:33PM +0100, Matthew Auld wrote:
> Export get/unmap/free pages API. We also need to tweak the SVM init to
> allow skipping much of the unneeded parts.
>
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Matthew Brost <matthew.brost@intel.com>
> ---
> drivers/gpu/drm/drm_gpusvm.c | 66 ++++++++++++++++++++++++++++--------
> include/drm/drm_gpusvm.h | 16 +++++++++
> 2 files changed, 67 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
> index fbe0d70ef163..0e0a3c995b4b 100644
> --- a/drivers/gpu/drm/drm_gpusvm.c
> +++ b/drivers/gpu/drm/drm_gpusvm.c
> @@ -539,6 +539,12 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
> *
> * This function initializes the GPU SVM.
> *
> + * Note: If only using the simple drm_gpusvm_pages API (get/unmap/free),
> + * then only @gpusvm, @name, and @drm are expected. However, the same base
> + * @gpusvm can also be used with both modes together in which case the full
> + * setup is needed, where the core drm_gpusvm_pages API will simply never use
> + * the other fields.
> + *
> * Return: 0 on success, a negative error code on failure.
> */
> int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
> @@ -549,8 +555,16 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
> const struct drm_gpusvm_ops *ops,
> const unsigned long *chunk_sizes, int num_chunks)
> {
> - if (!ops->invalidate || !num_chunks)
> - return -EINVAL;
> + if (mm) {
Do you still need this if statement if GPU SVM is shared between userptr
and SVM? Shouldn't we always pass in the MM?
Or is this for the mode where SVM is disabled in Xe and we just use the
get_pages functionality?
Matt
> + if (!ops->invalidate || !num_chunks)
> + return -EINVAL;
> + mmgrab(mm);
> + } else {
> + /* No full SVM mode, only core drm_gpusvm_pages API. */
> + if (ops || num_chunks || mm_range || notifier_size ||
> + device_private_page_owner)
> + return -EINVAL;
> + }
>
> gpusvm->name = name;
> gpusvm->drm = drm;
> @@ -563,7 +577,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
> gpusvm->chunk_sizes = chunk_sizes;
> gpusvm->num_chunks = num_chunks;
>
> - mmgrab(mm);
> gpusvm->root = RB_ROOT_CACHED;
> INIT_LIST_HEAD(&gpusvm->notifier_list);
>
> @@ -671,7 +684,8 @@ void drm_gpusvm_fini(struct drm_gpusvm *gpusvm)
> drm_gpusvm_range_remove(gpusvm, range);
> }
>
> - mmdrop(gpusvm->mm);
> + if (gpusvm->mm)
> + mmdrop(gpusvm->mm);
> WARN_ON(!RB_EMPTY_ROOT(&gpusvm->root.rb_root));
> }
> EXPORT_SYMBOL_GPL(drm_gpusvm_fini);
> @@ -1185,6 +1199,27 @@ static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> }
> }
>
> +/**
> + * drm_gpusvm_free_pages() - Free dma-mapping associated with GPU SVM pages
> + * struct
> + * @gpusvm: Pointer to the GPU SVM structure
> + * @svm_pages: Pointer to the GPU SVM pages structure
> + * @npages: Number of mapped pages
> + *
> + * This function unmaps and frees the dma address array associated with a GPU
> + * SVM pages struct.
> + */
> +void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + unsigned long npages)
> +{
> + drm_gpusvm_notifier_lock(gpusvm);
> + __drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages);
> + __drm_gpusvm_free_pages(gpusvm, svm_pages);
> + drm_gpusvm_notifier_unlock(gpusvm);
> +}
> +EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages);
> +
> /**
> * drm_gpusvm_range_remove() - Remove GPU SVM range
> * @gpusvm: Pointer to the GPU SVM structure
> @@ -1360,13 +1395,12 @@ static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
> *
> * Return: 0 on success, negative error code on failure.
> */
> -static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> - struct drm_gpusvm_pages *svm_pages,
> - struct mm_struct *mm,
> - struct mmu_interval_notifier *notifier,
> - unsigned long pages_start,
> - unsigned long pages_end,
> - const struct drm_gpusvm_ctx *ctx)
> +int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + struct mm_struct *mm,
> + struct mmu_interval_notifier *notifier,
> + unsigned long pages_start, unsigned long pages_end,
> + const struct drm_gpusvm_ctx *ctx)
> {
> struct hmm_range hmm_range = {
> .default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
> @@ -1548,6 +1582,7 @@ static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> goto retry;
> return err;
> }
> +EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages);
>
> /**
> * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
> @@ -1583,10 +1618,10 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
> * Must be called in the invalidate() callback of the corresponding notifier for
> * IOMMU security model.
> */
> -static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> - struct drm_gpusvm_pages *svm_pages,
> - unsigned long npages,
> - const struct drm_gpusvm_ctx *ctx)
> +void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + unsigned long npages,
> + const struct drm_gpusvm_ctx *ctx)
> {
> if (ctx->in_notifier)
> lockdep_assert_held_write(&gpusvm->notifier_lock);
> @@ -1598,6 +1633,7 @@ static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> if (!ctx->in_notifier)
> drm_gpusvm_notifier_unlock(gpusvm);
> }
> +EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages);
>
> /**
> * drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
> diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
> index 1b7ed4f4a8e2..611aaba1ac80 100644
> --- a/include/drm/drm_gpusvm.h
> +++ b/include/drm/drm_gpusvm.h
> @@ -370,6 +370,22 @@ void drm_gpusvm_devmem_init(struct drm_gpusvm_devmem *devmem_allocation,
> const struct drm_gpusvm_devmem_ops *ops,
> struct drm_pagemap *dpagemap, size_t size);
>
> +int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + struct mm_struct *mm,
> + struct mmu_interval_notifier *notifier,
> + unsigned long pages_start, unsigned long pages_end,
> + const struct drm_gpusvm_ctx *ctx);
> +
> +void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + unsigned long npages,
> + const struct drm_gpusvm_ctx *ctx);
> +
> +void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> + struct drm_gpusvm_pages *svm_pages,
> + unsigned long npages);
> +
> #ifdef CONFIG_LOCKDEP
> /**
> * drm_gpusvm_driver_set_lock() - Set the lock protecting accesses to GPU SVM
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API
2025-04-24 22:01 ` Matthew Brost
@ 2025-04-24 22:04 ` Matthew Brost
0 siblings, 0 replies; 18+ messages in thread
From: Matthew Brost @ 2025-04-24 22:04 UTC (permalink / raw)
To: Matthew Auld; +Cc: intel-xe, dri-devel, Thomas Hellström
On Thu, Apr 24, 2025 at 03:01:21PM -0700, Matthew Brost wrote:
> On Thu, Apr 24, 2025 at 01:18:33PM +0100, Matthew Auld wrote:
> > Export get/unmap/free pages API. We also need to tweak the SVM init to
> > allow skipping much of the unneeded parts.
> >
> > Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> > Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> > Cc: Matthew Brost <matthew.brost@intel.com>
> > ---
> > drivers/gpu/drm/drm_gpusvm.c | 66 ++++++++++++++++++++++++++++--------
> > include/drm/drm_gpusvm.h | 16 +++++++++
> > 2 files changed, 67 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
> > index fbe0d70ef163..0e0a3c995b4b 100644
> > --- a/drivers/gpu/drm/drm_gpusvm.c
> > +++ b/drivers/gpu/drm/drm_gpusvm.c
> > @@ -539,6 +539,12 @@ static const struct mmu_interval_notifier_ops drm_gpusvm_notifier_ops = {
> > *
> > * This function initializes the GPU SVM.
> > *
> > + * Note: If only using the simple drm_gpusvm_pages API (get/unmap/free),
> > + * then only @gpusvm, @name, and @drm are expected. However, the same base
> > + * @gpusvm can also be used with both modes together in which case the full
> > + * setup is needed, where the core drm_gpusvm_pages API will simply never use
> > + * the other fields.
> > + *
> > * Return: 0 on success, a negative error code on failure.
> > */
> > int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
> > @@ -549,8 +555,16 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
> > const struct drm_gpusvm_ops *ops,
> > const unsigned long *chunk_sizes, int num_chunks)
> > {
> > - if (!ops->invalidate || !num_chunks)
> > - return -EINVAL;
> > + if (mm) {
>
> Do you still need this if statement if GPU SVM is shared between userptr
> and SVM? Shouldn't we always pass in the MM?
>
> Or is this for the mode where SVM is disabled in Xe and we just use the
> get_pages functionality?
>
Nevermind, I see how this is used in the following patch. Make sense.
With that:
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
> Matt
>
> > + if (!ops->invalidate || !num_chunks)
> > + return -EINVAL;
> > + mmgrab(mm);
> > + } else {
> > + /* No full SVM mode, only core drm_gpusvm_pages API. */
> > + if (ops || num_chunks || mm_range || notifier_size ||
> > + device_private_page_owner)
> > + return -EINVAL;
> > + }
> >
> > gpusvm->name = name;
> > gpusvm->drm = drm;
> > @@ -563,7 +577,6 @@ int drm_gpusvm_init(struct drm_gpusvm *gpusvm,
> > gpusvm->chunk_sizes = chunk_sizes;
> > gpusvm->num_chunks = num_chunks;
> >
> > - mmgrab(mm);
> > gpusvm->root = RB_ROOT_CACHED;
> > INIT_LIST_HEAD(&gpusvm->notifier_list);
> >
> > @@ -671,7 +684,8 @@ void drm_gpusvm_fini(struct drm_gpusvm *gpusvm)
> > drm_gpusvm_range_remove(gpusvm, range);
> > }
> >
> > - mmdrop(gpusvm->mm);
> > + if (gpusvm->mm)
> > + mmdrop(gpusvm->mm);
> > WARN_ON(!RB_EMPTY_ROOT(&gpusvm->root.rb_root));
> > }
> > EXPORT_SYMBOL_GPL(drm_gpusvm_fini);
> > @@ -1185,6 +1199,27 @@ static void __drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> > }
> > }
> >
> > +/**
> > + * drm_gpusvm_free_pages() - Free dma-mapping associated with GPU SVM pages
> > + * struct
> > + * @gpusvm: Pointer to the GPU SVM structure
> > + * @svm_pages: Pointer to the GPU SVM pages structure
> > + * @npages: Number of mapped pages
> > + *
> > + * This function unmaps and frees the dma address array associated with a GPU
> > + * SVM pages struct.
> > + */
> > +void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> > + struct drm_gpusvm_pages *svm_pages,
> > + unsigned long npages)
> > +{
> > + drm_gpusvm_notifier_lock(gpusvm);
> > + __drm_gpusvm_unmap_pages(gpusvm, svm_pages, npages);
> > + __drm_gpusvm_free_pages(gpusvm, svm_pages);
> > + drm_gpusvm_notifier_unlock(gpusvm);
> > +}
> > +EXPORT_SYMBOL_GPL(drm_gpusvm_free_pages);
> > +
> > /**
> > * drm_gpusvm_range_remove() - Remove GPU SVM range
> > * @gpusvm: Pointer to the GPU SVM structure
> > @@ -1360,13 +1395,12 @@ static bool drm_gpusvm_pages_valid_unlocked(struct drm_gpusvm *gpusvm,
> > *
> > * Return: 0 on success, negative error code on failure.
> > */
> > -static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> > - struct drm_gpusvm_pages *svm_pages,
> > - struct mm_struct *mm,
> > - struct mmu_interval_notifier *notifier,
> > - unsigned long pages_start,
> > - unsigned long pages_end,
> > - const struct drm_gpusvm_ctx *ctx)
> > +int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> > + struct drm_gpusvm_pages *svm_pages,
> > + struct mm_struct *mm,
> > + struct mmu_interval_notifier *notifier,
> > + unsigned long pages_start, unsigned long pages_end,
> > + const struct drm_gpusvm_ctx *ctx)
> > {
> > struct hmm_range hmm_range = {
> > .default_flags = HMM_PFN_REQ_FAULT | (ctx->read_only ? 0 :
> > @@ -1548,6 +1582,7 @@ static int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> > goto retry;
> > return err;
> > }
> > +EXPORT_SYMBOL_GPL(drm_gpusvm_get_pages);
> >
> > /**
> > * drm_gpusvm_range_get_pages() - Get pages for a GPU SVM range
> > @@ -1583,10 +1618,10 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_range_get_pages);
> > * Must be called in the invalidate() callback of the corresponding notifier for
> > * IOMMU security model.
> > */
> > -static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> > - struct drm_gpusvm_pages *svm_pages,
> > - unsigned long npages,
> > - const struct drm_gpusvm_ctx *ctx)
> > +void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> > + struct drm_gpusvm_pages *svm_pages,
> > + unsigned long npages,
> > + const struct drm_gpusvm_ctx *ctx)
> > {
> > if (ctx->in_notifier)
> > lockdep_assert_held_write(&gpusvm->notifier_lock);
> > @@ -1598,6 +1633,7 @@ static void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> > if (!ctx->in_notifier)
> > drm_gpusvm_notifier_unlock(gpusvm);
> > }
> > +EXPORT_SYMBOL_GPL(drm_gpusvm_unmap_pages);
> >
> > /**
> > * drm_gpusvm_range_unmap_pages() - Unmap pages associated with a GPU SVM range
> > diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
> > index 1b7ed4f4a8e2..611aaba1ac80 100644
> > --- a/include/drm/drm_gpusvm.h
> > +++ b/include/drm/drm_gpusvm.h
> > @@ -370,6 +370,22 @@ void drm_gpusvm_devmem_init(struct drm_gpusvm_devmem *devmem_allocation,
> > const struct drm_gpusvm_devmem_ops *ops,
> > struct drm_pagemap *dpagemap, size_t size);
> >
> > +int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> > + struct drm_gpusvm_pages *svm_pages,
> > + struct mm_struct *mm,
> > + struct mmu_interval_notifier *notifier,
> > + unsigned long pages_start, unsigned long pages_end,
> > + const struct drm_gpusvm_ctx *ctx);
> > +
> > +void drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> > + struct drm_gpusvm_pages *svm_pages,
> > + unsigned long npages,
> > + const struct drm_gpusvm_ctx *ctx);
> > +
> > +void drm_gpusvm_free_pages(struct drm_gpusvm *gpusvm,
> > + struct drm_gpusvm_pages *svm_pages,
> > + unsigned long npages);
> > +
> > #ifdef CONFIG_LOCKDEP
> > /**
> > * drm_gpusvm_driver_set_lock() - Set the lock protecting accesses to GPU SVM
> > --
> > 2.49.0
> >
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
2025-04-24 14:21 ` kernel test robot
2025-04-24 14:42 ` kernel test robot
@ 2025-04-24 23:17 ` Matthew Brost
2025-04-25 14:00 ` kernel test robot
2025-04-28 3:47 ` Dafna Hirschfeld
4 siblings, 0 replies; 18+ messages in thread
From: Matthew Brost @ 2025-04-24 23:17 UTC (permalink / raw)
To: Matthew Auld
Cc: intel-xe, dri-devel, Himal Prasad Ghimiray, Thomas Hellström
On Thu, Apr 24, 2025 at 01:18:34PM +0100, Matthew Auld wrote:
> Goal here is cut over to gpusvm and remove xe_hmm, relying instead on
> common code. The core facilities we need are get_pages(), unmap_pages()
> and free_pages() for a given useptr range, plus a vm level notifier
> lock, which is now provided by gpusvm.
>
> v2:
> - Reuse the same SVM vm struct we use for full SVM, that way we can
> use the same lock (Matt B & Himal)
> v3:
> - Re-use svm_init/fini for userptr.
>
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Cc: Matthew Brost <matthew.brost@intel.com>
> ---
> drivers/gpu/drm/xe/Kconfig | 3 +-
> drivers/gpu/drm/xe/Makefile | 1 -
> drivers/gpu/drm/xe/xe_exec.c | 4 +-
> drivers/gpu/drm/xe/xe_hmm.c | 325 -------------------------------
> drivers/gpu/drm/xe/xe_hmm.h | 18 --
> drivers/gpu/drm/xe/xe_pt.c | 22 +--
> drivers/gpu/drm/xe/xe_svm.c | 32 +--
> drivers/gpu/drm/xe/xe_svm.h | 6 +-
> drivers/gpu/drm/xe/xe_vm.c | 86 ++++----
> drivers/gpu/drm/xe/xe_vm_types.h | 26 +--
> 10 files changed, 92 insertions(+), 431 deletions(-)
> delete mode 100644 drivers/gpu/drm/xe/xe_hmm.c
> delete mode 100644 drivers/gpu/drm/xe/xe_hmm.h
>
> diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
> index 9bce047901b2..1e63dde76c55 100644
> --- a/drivers/gpu/drm/xe/Kconfig
> +++ b/drivers/gpu/drm/xe/Kconfig
> @@ -43,7 +43,7 @@ config DRM_XE
> select MMU_NOTIFIER
> select WANT_DEV_COREDUMP
> select AUXILIARY_BUS
> - select HMM_MIRROR
> + select DRM_GPUSVM
select DRM_GPUSVM if !UML and DEVICE_PRIVATE
GPUSVM won't compile on UML. That might have other implictions
throughout the driver (e.g. compile out parts of userptr, disable
userptr if at IOCTLs if DRM_GPUSVM is not selected, etc...).
Rest of the patch LGTM.
Matt
> help
> Experimental driver for Intel Xe series GPUs
>
> @@ -79,7 +79,6 @@ config DRM_XE_GPUSVM
> depends on !UML
> depends on DEVICE_PRIVATE
> default y
> - select DRM_GPUSVM
> help
> Enable this option if you want support for CPU to GPU address
> mirroring.
> diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
> index 3ecac0a38b82..f1123be158f8 100644
> --- a/drivers/gpu/drm/xe/Makefile
> +++ b/drivers/gpu/drm/xe/Makefile
> @@ -124,7 +124,6 @@ xe-y += xe_bb.o \
> xe_wait_user_fence.o \
> xe_wopcm.o
>
> -xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
> xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
>
> # graphics hardware monitoring (HWMON) support
> diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
> index b75adfc99fb7..c0ce681076d5 100644
> --- a/drivers/gpu/drm/xe/xe_exec.c
> +++ b/drivers/gpu/drm/xe/xe_exec.c
> @@ -294,7 +294,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
> if (err)
> goto err_put_job;
>
> - err = down_read_interruptible(&vm->userptr.notifier_lock);
> + err = down_read_interruptible(&vm->svm.gpusvm.notifier_lock);
> if (err)
> goto err_put_job;
>
> @@ -336,7 +336,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>
> err_repin:
> if (!xe_vm_in_lr_mode(vm))
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> err_put_job:
> if (err)
> xe_sched_job_put(job);
> diff --git a/drivers/gpu/drm/xe/xe_hmm.c b/drivers/gpu/drm/xe/xe_hmm.c
> deleted file mode 100644
> index 57b71956ddf4..000000000000
> --- a/drivers/gpu/drm/xe/xe_hmm.c
> +++ /dev/null
> @@ -1,325 +0,0 @@
> -// SPDX-License-Identifier: MIT
> -/*
> - * Copyright © 2024 Intel Corporation
> - */
> -
> -#include <linux/scatterlist.h>
> -#include <linux/mmu_notifier.h>
> -#include <linux/dma-mapping.h>
> -#include <linux/memremap.h>
> -#include <linux/swap.h>
> -#include <linux/hmm.h>
> -#include <linux/mm.h>
> -#include "xe_hmm.h"
> -#include "xe_vm.h"
> -#include "xe_bo.h"
> -
> -static u64 xe_npages_in_range(unsigned long start, unsigned long end)
> -{
> - return (end - start) >> PAGE_SHIFT;
> -}
> -
> -static int xe_alloc_sg(struct xe_device *xe, struct sg_table *st,
> - struct hmm_range *range, struct rw_semaphore *notifier_sem)
> -{
> - unsigned long i, npages, hmm_pfn;
> - unsigned long num_chunks = 0;
> - int ret;
> -
> - /* HMM docs says this is needed. */
> - ret = down_read_interruptible(notifier_sem);
> - if (ret)
> - return ret;
> -
> - if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) {
> - up_read(notifier_sem);
> - return -EAGAIN;
> - }
> -
> - npages = xe_npages_in_range(range->start, range->end);
> - for (i = 0; i < npages;) {
> - unsigned long len;
> -
> - hmm_pfn = range->hmm_pfns[i];
> - xe_assert(xe, hmm_pfn & HMM_PFN_VALID);
> -
> - len = 1UL << hmm_pfn_to_map_order(hmm_pfn);
> -
> - /* If order > 0 the page may extend beyond range->start */
> - len -= (hmm_pfn & ~HMM_PFN_FLAGS) & (len - 1);
> - i += len;
> - num_chunks++;
> - }
> - up_read(notifier_sem);
> -
> - return sg_alloc_table(st, num_chunks, GFP_KERNEL);
> -}
> -
> -/**
> - * xe_build_sg() - build a scatter gather table for all the physical pages/pfn
> - * in a hmm_range. dma-map pages if necessary. dma-address is save in sg table
> - * and will be used to program GPU page table later.
> - * @xe: the xe device who will access the dma-address in sg table
> - * @range: the hmm range that we build the sg table from. range->hmm_pfns[]
> - * has the pfn numbers of pages that back up this hmm address range.
> - * @st: pointer to the sg table.
> - * @notifier_sem: The xe notifier lock.
> - * @write: whether we write to this range. This decides dma map direction
> - * for system pages. If write we map it bi-diretional; otherwise
> - * DMA_TO_DEVICE
> - *
> - * All the contiguous pfns will be collapsed into one entry in
> - * the scatter gather table. This is for the purpose of efficiently
> - * programming GPU page table.
> - *
> - * The dma_address in the sg table will later be used by GPU to
> - * access memory. So if the memory is system memory, we need to
> - * do a dma-mapping so it can be accessed by GPU/DMA.
> - *
> - * FIXME: This function currently only support pages in system
> - * memory. If the memory is GPU local memory (of the GPU who
> - * is going to access memory), we need gpu dpa (device physical
> - * address), and there is no need of dma-mapping. This is TBD.
> - *
> - * FIXME: dma-mapping for peer gpu device to access remote gpu's
> - * memory. Add this when you support p2p
> - *
> - * This function allocates the storage of the sg table. It is
> - * caller's responsibility to free it calling sg_free_table.
> - *
> - * Returns 0 if successful; -ENOMEM if fails to allocate memory
> - */
> -static int xe_build_sg(struct xe_device *xe, struct hmm_range *range,
> - struct sg_table *st,
> - struct rw_semaphore *notifier_sem,
> - bool write)
> -{
> - unsigned long npages = xe_npages_in_range(range->start, range->end);
> - struct device *dev = xe->drm.dev;
> - struct scatterlist *sgl;
> - struct page *page;
> - unsigned long i, j;
> -
> - lockdep_assert_held(notifier_sem);
> -
> - i = 0;
> - for_each_sg(st->sgl, sgl, st->nents, j) {
> - unsigned long hmm_pfn, size;
> -
> - hmm_pfn = range->hmm_pfns[i];
> - page = hmm_pfn_to_page(hmm_pfn);
> - xe_assert(xe, !is_device_private_page(page));
> -
> - size = 1UL << hmm_pfn_to_map_order(hmm_pfn);
> - size -= page_to_pfn(page) & (size - 1);
> - i += size;
> -
> - if (unlikely(j == st->nents - 1)) {
> - xe_assert(xe, i >= npages);
> - if (i > npages)
> - size -= (i - npages);
> -
> - sg_mark_end(sgl);
> - } else {
> - xe_assert(xe, i < npages);
> - }
> -
> - sg_set_page(sgl, page, size << PAGE_SHIFT, 0);
> - }
> -
> - return dma_map_sgtable(dev, st, write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE,
> - DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_NO_KERNEL_MAPPING);
> -}
> -
> -static void xe_hmm_userptr_set_mapped(struct xe_userptr_vma *uvma)
> -{
> - struct xe_userptr *userptr = &uvma->userptr;
> - struct xe_vm *vm = xe_vma_vm(&uvma->vma);
> -
> - lockdep_assert_held_write(&vm->lock);
> - lockdep_assert_held(&vm->userptr.notifier_lock);
> -
> - mutex_lock(&userptr->unmap_mutex);
> - xe_assert(vm->xe, !userptr->mapped);
> - userptr->mapped = true;
> - mutex_unlock(&userptr->unmap_mutex);
> -}
> -
> -void xe_hmm_userptr_unmap(struct xe_userptr_vma *uvma)
> -{
> - struct xe_userptr *userptr = &uvma->userptr;
> - struct xe_vma *vma = &uvma->vma;
> - bool write = !xe_vma_read_only(vma);
> - struct xe_vm *vm = xe_vma_vm(vma);
> - struct xe_device *xe = vm->xe;
> -
> - if (!lockdep_is_held_type(&vm->userptr.notifier_lock, 0) &&
> - !lockdep_is_held_type(&vm->lock, 0) &&
> - !(vma->gpuva.flags & XE_VMA_DESTROYED)) {
> - /* Don't unmap in exec critical section. */
> - xe_vm_assert_held(vm);
> - /* Don't unmap while mapping the sg. */
> - lockdep_assert_held(&vm->lock);
> - }
> -
> - mutex_lock(&userptr->unmap_mutex);
> - if (userptr->sg && userptr->mapped)
> - dma_unmap_sgtable(xe->drm.dev, userptr->sg,
> - write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE, 0);
> - userptr->mapped = false;
> - mutex_unlock(&userptr->unmap_mutex);
> -}
> -
> -/**
> - * xe_hmm_userptr_free_sg() - Free the scatter gather table of userptr
> - * @uvma: the userptr vma which hold the scatter gather table
> - *
> - * With function xe_userptr_populate_range, we allocate storage of
> - * the userptr sg table. This is a helper function to free this
> - * sg table, and dma unmap the address in the table.
> - */
> -void xe_hmm_userptr_free_sg(struct xe_userptr_vma *uvma)
> -{
> - struct xe_userptr *userptr = &uvma->userptr;
> -
> - xe_assert(xe_vma_vm(&uvma->vma)->xe, userptr->sg);
> - xe_hmm_userptr_unmap(uvma);
> - sg_free_table(userptr->sg);
> - userptr->sg = NULL;
> -}
> -
> -/**
> - * xe_hmm_userptr_populate_range() - Populate physical pages of a virtual
> - * address range
> - *
> - * @uvma: userptr vma which has information of the range to populate.
> - * @is_mm_mmap_locked: True if mmap_read_lock is already acquired by caller.
> - *
> - * This function populate the physical pages of a virtual
> - * address range. The populated physical pages is saved in
> - * userptr's sg table. It is similar to get_user_pages but call
> - * hmm_range_fault.
> - *
> - * This function also read mmu notifier sequence # (
> - * mmu_interval_read_begin), for the purpose of later
> - * comparison (through mmu_interval_read_retry).
> - *
> - * This must be called with mmap read or write lock held.
> - *
> - * This function allocates the storage of the userptr sg table.
> - * It is caller's responsibility to free it calling sg_free_table.
> - *
> - * returns: 0 for success; negative error no on failure
> - */
> -int xe_hmm_userptr_populate_range(struct xe_userptr_vma *uvma,
> - bool is_mm_mmap_locked)
> -{
> - unsigned long timeout =
> - jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
> - unsigned long *pfns;
> - struct xe_userptr *userptr;
> - struct xe_vma *vma = &uvma->vma;
> - u64 userptr_start = xe_vma_userptr(vma);
> - u64 userptr_end = userptr_start + xe_vma_size(vma);
> - struct xe_vm *vm = xe_vma_vm(vma);
> - struct hmm_range hmm_range = {
> - .pfn_flags_mask = 0, /* ignore pfns */
> - .default_flags = HMM_PFN_REQ_FAULT,
> - .start = userptr_start,
> - .end = userptr_end,
> - .notifier = &uvma->userptr.notifier,
> - .dev_private_owner = vm->xe,
> - };
> - bool write = !xe_vma_read_only(vma);
> - unsigned long notifier_seq;
> - u64 npages;
> - int ret;
> -
> - userptr = &uvma->userptr;
> -
> - if (is_mm_mmap_locked)
> - mmap_assert_locked(userptr->notifier.mm);
> -
> - if (vma->gpuva.flags & XE_VMA_DESTROYED)
> - return 0;
> -
> - notifier_seq = mmu_interval_read_begin(&userptr->notifier);
> - if (notifier_seq == userptr->notifier_seq)
> - return 0;
> -
> - if (userptr->sg)
> - xe_hmm_userptr_free_sg(uvma);
> -
> - npages = xe_npages_in_range(userptr_start, userptr_end);
> - pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
> - if (unlikely(!pfns))
> - return -ENOMEM;
> -
> - if (write)
> - hmm_range.default_flags |= HMM_PFN_REQ_WRITE;
> -
> - if (!mmget_not_zero(userptr->notifier.mm)) {
> - ret = -EFAULT;
> - goto free_pfns;
> - }
> -
> - hmm_range.hmm_pfns = pfns;
> -
> - while (true) {
> - hmm_range.notifier_seq = mmu_interval_read_begin(&userptr->notifier);
> -
> - if (!is_mm_mmap_locked)
> - mmap_read_lock(userptr->notifier.mm);
> -
> - ret = hmm_range_fault(&hmm_range);
> -
> - if (!is_mm_mmap_locked)
> - mmap_read_unlock(userptr->notifier.mm);
> -
> - if (ret == -EBUSY) {
> - if (time_after(jiffies, timeout))
> - break;
> -
> - continue;
> - }
> - break;
> - }
> -
> - mmput(userptr->notifier.mm);
> -
> - if (ret)
> - goto free_pfns;
> -
> - ret = xe_alloc_sg(vm->xe, &userptr->sgt, &hmm_range, &vm->userptr.notifier_lock);
> - if (ret)
> - goto free_pfns;
> -
> - ret = down_read_interruptible(&vm->userptr.notifier_lock);
> - if (ret)
> - goto free_st;
> -
> - if (mmu_interval_read_retry(hmm_range.notifier, hmm_range.notifier_seq)) {
> - ret = -EAGAIN;
> - goto out_unlock;
> - }
> -
> - ret = xe_build_sg(vm->xe, &hmm_range, &userptr->sgt,
> - &vm->userptr.notifier_lock, write);
> - if (ret)
> - goto out_unlock;
> -
> - userptr->sg = &userptr->sgt;
> - xe_hmm_userptr_set_mapped(uvma);
> - userptr->notifier_seq = hmm_range.notifier_seq;
> - up_read(&vm->userptr.notifier_lock);
> - kvfree(pfns);
> - return 0;
> -
> -out_unlock:
> - up_read(&vm->userptr.notifier_lock);
> -free_st:
> - sg_free_table(&userptr->sgt);
> -free_pfns:
> - kvfree(pfns);
> - return ret;
> -}
> diff --git a/drivers/gpu/drm/xe/xe_hmm.h b/drivers/gpu/drm/xe/xe_hmm.h
> deleted file mode 100644
> index 0ea98d8e7bbc..000000000000
> --- a/drivers/gpu/drm/xe/xe_hmm.h
> +++ /dev/null
> @@ -1,18 +0,0 @@
> -/* SPDX-License-Identifier: MIT
> - *
> - * Copyright © 2024 Intel Corporation
> - */
> -
> -#ifndef _XE_HMM_H_
> -#define _XE_HMM_H_
> -
> -#include <linux/types.h>
> -
> -struct xe_userptr_vma;
> -
> -int xe_hmm_userptr_populate_range(struct xe_userptr_vma *uvma, bool is_mm_mmap_locked);
> -
> -void xe_hmm_userptr_free_sg(struct xe_userptr_vma *uvma);
> -
> -void xe_hmm_userptr_unmap(struct xe_userptr_vma *uvma);
> -#endif
> diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
> index 5cccfd9cc3e9..ff898e518afd 100644
> --- a/drivers/gpu/drm/xe/xe_pt.c
> +++ b/drivers/gpu/drm/xe/xe_pt.c
> @@ -756,8 +756,8 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
>
> if (!xe_vma_is_null(vma) && !range) {
> if (xe_vma_is_userptr(vma))
> - xe_res_first_sg(to_userptr_vma(vma)->userptr.sg, 0,
> - xe_vma_size(vma), &curs);
> + xe_res_first_dma(to_userptr_vma(vma)->userptr.pages.dma_addr, 0,
> + xe_vma_size(vma), &curs);
> else if (xe_bo_is_vram(bo) || xe_bo_is_stolen(bo))
> xe_res_first(bo->ttm.resource, xe_vma_bo_offset(vma),
> xe_vma_size(vma), &curs);
> @@ -1028,7 +1028,7 @@ static void xe_pt_commit_locks_assert(struct xe_vma *vma)
> xe_pt_commit_prepare_locks_assert(vma);
>
> if (xe_vma_is_userptr(vma))
> - lockdep_assert_held_read(&vm->userptr.notifier_lock);
> + lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
> }
>
> static void xe_pt_commit(struct xe_vma *vma,
> @@ -1368,7 +1368,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
> struct xe_userptr_vma *uvma;
> unsigned long notifier_seq;
>
> - lockdep_assert_held_read(&vm->userptr.notifier_lock);
> + lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> if (!xe_vma_is_userptr(vma))
> return 0;
> @@ -1377,7 +1377,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
> if (xe_pt_userptr_inject_eagain(uvma))
> xe_vma_userptr_force_invalidate(uvma);
>
> - notifier_seq = uvma->userptr.notifier_seq;
> + notifier_seq = uvma->userptr.pages.notifier_seq;
>
> if (!mmu_interval_read_retry(&uvma->userptr.notifier,
> notifier_seq))
> @@ -1398,7 +1398,7 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
> {
> int err = 0;
>
> - lockdep_assert_held_read(&vm->userptr.notifier_lock);
> + lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> switch (op->base.op) {
> case DRM_GPUVA_OP_MAP:
> @@ -1439,12 +1439,12 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
> if (err)
> return err;
>
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
>
> list_for_each_entry(op, &vops->list, link) {
> err = op_check_userptr(vm, op, pt_update_ops);
> if (err) {
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> break;
> }
> }
> @@ -2171,7 +2171,7 @@ static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
> if (invalidate_on_bind)
> vma->tile_invalidated |= BIT(tile->id);
> if (xe_vma_is_userptr(vma)) {
> - lockdep_assert_held_read(&vm->userptr.notifier_lock);
> + lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
> to_userptr_vma(vma)->userptr.initial_bind = true;
> }
>
> @@ -2207,7 +2207,7 @@ static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
> if (!vma->tile_present) {
> list_del_init(&vma->combined_links.rebind);
> if (xe_vma_is_userptr(vma)) {
> - lockdep_assert_held_read(&vm->userptr.notifier_lock);
> + lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> spin_lock(&vm->userptr.invalidated_lock);
> list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link);
> @@ -2456,7 +2456,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
> if (pt_update_ops->needs_svm_lock)
> xe_svm_notifier_unlock(vm);
> if (pt_update_ops->needs_userptr_lock)
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
>
> return fence;
>
> diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
> index f60c7f587cd6..10ec237ec88c 100644
> --- a/drivers/gpu/drm/xe/xe_svm.c
> +++ b/drivers/gpu/drm/xe/xe_svm.c
> @@ -606,22 +606,26 @@ int xe_svm_init(struct xe_vm *vm)
> {
> int err;
>
> - spin_lock_init(&vm->svm.garbage_collector.lock);
> - INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
> - INIT_WORK(&vm->svm.garbage_collector.work,
> - xe_svm_garbage_collector_work_func);
> + if (vm->flags & XE_VM_FLAG_FAULT_MODE) {
> + spin_lock_init(&vm->svm.garbage_collector.lock);
> + INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
> + INIT_WORK(&vm->svm.garbage_collector.work,
> + xe_svm_garbage_collector_work_func);
>
> - err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
> - current->mm, xe_svm_devm_owner(vm->xe), 0,
> - vm->size, xe_modparam.svm_notifier_size * SZ_1M,
> - &gpusvm_ops, fault_chunk_sizes,
> - ARRAY_SIZE(fault_chunk_sizes));
> - if (err)
> - return err;
> + err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
> + current->mm, xe_svm_devm_owner(vm->xe), 0,
> + vm->size,
> + xe_modparam.svm_notifier_size * SZ_1M,
> + &gpusvm_ops, fault_chunk_sizes,
> + ARRAY_SIZE(fault_chunk_sizes));
> + drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
> + } else {
> + err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
> + &vm->xe->drm, NULL, NULL, 0, 0, 0, NULL,
> + NULL, 0);
> + }
>
> - drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
> -
> - return 0;
> + return err;
> }
>
> /**
> diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
> index 8bc83de87250..923cb074d0cb 100644
> --- a/drivers/gpu/drm/xe/xe_svm.h
> +++ b/drivers/gpu/drm/xe/xe_svm.h
> @@ -134,12 +134,16 @@ int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr)
> static inline
> int xe_svm_init(struct xe_vm *vm)
> {
> - return 0;
> + return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
> + NULL, NULL, 0, 0, 0, NULL, NULL, 0);
> }
>
> static inline
> void xe_svm_fini(struct xe_vm *vm)
> {
> + xe_assert(vm->xe, xe_vm_is_closed(vm));
> +
> + drm_gpusvm_fini(&vm->svm.gpusvm);
> }
>
> static inline
> diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
> index 0c69ef6b5ec5..b900afe61931 100644
> --- a/drivers/gpu/drm/xe/xe_vm.c
> +++ b/drivers/gpu/drm/xe/xe_vm.c
> @@ -40,7 +40,6 @@
> #include "xe_sync.h"
> #include "xe_trace_bo.h"
> #include "xe_wa.h"
> -#include "xe_hmm.h"
>
> static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> {
> @@ -53,7 +52,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> *
> * Check if the userptr vma has been invalidated since last successful
> * repin. The check is advisory only and can the function can be called
> - * without the vm->userptr.notifier_lock held. There is no guarantee that the
> + * without the vm->svm.gpusvm.notifier_lock held. There is no guarantee that the
> * vma userptr will remain valid after a lockless check, so typically
> * the call needs to be followed by a proper check under the notifier_lock.
> *
> @@ -62,7 +61,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma)
> {
> return mmu_interval_check_retry(&uvma->userptr.notifier,
> - uvma->userptr.notifier_seq) ?
> + uvma->userptr.pages.notifier_seq) ?
> -EAGAIN : 0;
> }
>
> @@ -71,11 +70,22 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
> struct xe_vma *vma = &uvma->vma;
> struct xe_vm *vm = xe_vma_vm(vma);
> struct xe_device *xe = vm->xe;
> + struct drm_gpusvm_ctx ctx = {
> + .read_only = xe_vma_read_only(vma),
> + };
>
> lockdep_assert_held(&vm->lock);
> xe_assert(xe, xe_vma_is_userptr(vma));
>
> - return xe_hmm_userptr_populate_range(uvma, false);
> + if (vma->gpuva.flags & XE_VMA_DESTROYED)
> + return 0;
> +
> + return drm_gpusvm_get_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
> + uvma->userptr.notifier.mm,
> + &uvma->userptr.notifier,
> + xe_vma_userptr(vma),
> + xe_vma_userptr(vma) + xe_vma_size(vma),
> + &ctx);
> }
>
> static bool preempt_fences_waiting(struct xe_vm *vm)
> @@ -249,7 +259,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
> ++vm->preempt.num_exec_queues;
> q->lr.pfence = pfence;
>
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
>
> drm_gpuvm_resv_add_fence(&vm->gpuvm, exec, pfence,
> DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_BOOKKEEP);
> @@ -263,7 +273,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
> if (wait)
> dma_fence_enable_sw_signaling(pfence);
>
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
>
> out_fini:
> drm_exec_fini(exec);
> @@ -305,14 +315,14 @@ void xe_vm_remove_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
> * @vm: The VM.
> *
> * This function checks for whether the VM has userptrs that need repinning,
> - * and provides a release-type barrier on the userptr.notifier_lock after
> + * and provides a release-type barrier on the svm.gpusvm.notifier_lock after
> * checking.
> *
> * Return: 0 if there are no userptrs needing repinning, -EAGAIN if there are.
> */
> int __xe_vm_userptr_needs_repin(struct xe_vm *vm)
> {
> - lockdep_assert_held_read(&vm->userptr.notifier_lock);
> + lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> return (list_empty(&vm->userptr.repin_list) &&
> list_empty(&vm->userptr.invalidated)) ? 0 : -EAGAIN;
> @@ -546,9 +556,9 @@ static void preempt_rebind_work_func(struct work_struct *w)
> (!(__tries)++ || __xe_vm_userptr_needs_repin(__vm)) : \
> __xe_vm_userptr_needs_repin(__vm))
>
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
> if (retry_required(tries, vm)) {
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> err = -EAGAIN;
> goto out_unlock;
> }
> @@ -562,7 +572,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
> /* Point of no return. */
> arm_preempt_fences(vm, &preempt_fences);
> resume_and_reinstall_preempt_fences(vm, &exec);
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
>
> out_unlock:
> drm_exec_fini(&exec);
> @@ -589,6 +599,9 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv
> struct xe_vma *vma = &uvma->vma;
> struct dma_resv_iter cursor;
> struct dma_fence *fence;
> + struct drm_gpusvm_ctx ctx = {
> + .in_notifier = true,
> + };
> long err;
>
> /*
> @@ -625,7 +638,8 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv
> XE_WARN_ON(err);
> }
>
> - xe_hmm_userptr_unmap(uvma);
> + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
> + xe_vma_size(vma) >> PAGE_SHIFT, &ctx);
> }
>
> static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
> @@ -646,11 +660,11 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
> "NOTIFIER: addr=0x%016llx, range=0x%016llx",
> xe_vma_start(vma), xe_vma_size(vma));
>
> - down_write(&vm->userptr.notifier_lock);
> + down_write(&vm->svm.gpusvm.notifier_lock);
> mmu_interval_set_seq(mni, cur_seq);
>
> __vma_userptr_invalidate(vm, uvma);
> - up_write(&vm->userptr.notifier_lock);
> + up_write(&vm->svm.gpusvm.notifier_lock);
> trace_xe_vma_userptr_invalidate_complete(vma);
>
> return true;
> @@ -674,7 +688,7 @@ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
> /* Protect against concurrent userptr pinning */
> lockdep_assert_held(&vm->lock);
> /* Protect against concurrent notifiers */
> - lockdep_assert_held(&vm->userptr.notifier_lock);
> + lockdep_assert_held(&vm->svm.gpusvm.notifier_lock);
> /*
> * Protect against concurrent instances of this function and
> * the critical exec sections
> @@ -747,7 +761,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
> }
>
> if (err) {
> - down_write(&vm->userptr.notifier_lock);
> + down_write(&vm->svm.gpusvm.notifier_lock);
> spin_lock(&vm->userptr.invalidated_lock);
> list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list,
> userptr.repin_link) {
> @@ -756,7 +770,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
> &vm->userptr.invalidated);
> }
> spin_unlock(&vm->userptr.invalidated_lock);
> - up_write(&vm->userptr.notifier_lock);
> + up_write(&vm->svm.gpusvm.notifier_lock);
> }
> return err;
> }
> @@ -1222,7 +1236,6 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
> INIT_LIST_HEAD(&userptr->invalidate_link);
> INIT_LIST_HEAD(&userptr->repin_link);
> vma->gpuva.gem.offset = bo_offset_or_userptr;
> - mutex_init(&userptr->unmap_mutex);
>
> err = mmu_interval_notifier_insert(&userptr->notifier,
> current->mm,
> @@ -1233,7 +1246,7 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
> return ERR_PTR(err);
> }
>
> - userptr->notifier_seq = LONG_MAX;
> + userptr->pages.notifier_seq = LONG_MAX;
> }
>
> xe_vm_get(vm);
> @@ -1255,8 +1268,8 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
> struct xe_userptr_vma *uvma = to_userptr_vma(vma);
> struct xe_userptr *userptr = &uvma->userptr;
>
> - if (userptr->sg)
> - xe_hmm_userptr_free_sg(uvma);
> + drm_gpusvm_free_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
> + xe_vma_size(vma) >> PAGE_SHIFT);
>
> /*
> * Since userptr pages are not pinned, we can't remove
> @@ -1264,7 +1277,6 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
> * them anymore
> */
> mmu_interval_notifier_remove(&userptr->notifier);
> - mutex_destroy(&userptr->unmap_mutex);
> xe_vm_put(vm);
> } else if (xe_vma_is_null(vma) || xe_vma_is_cpu_addr_mirror(vma)) {
> xe_vm_put(vm);
> @@ -1657,7 +1669,6 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
>
> INIT_LIST_HEAD(&vm->userptr.repin_list);
> INIT_LIST_HEAD(&vm->userptr.invalidated);
> - init_rwsem(&vm->userptr.notifier_lock);
> spin_lock_init(&vm->userptr.invalidated_lock);
>
> ttm_lru_bulk_move_init(&vm->lru_bulk_move);
> @@ -1757,11 +1768,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
> }
> }
>
> - if (flags & XE_VM_FLAG_FAULT_MODE) {
> - err = xe_svm_init(vm);
> - if (err)
> - goto err_close;
> - }
> + err = xe_svm_init(vm);
> + if (err)
> + goto err_close;
>
> if (number_tiles > 1)
> vm->composite_fence_ctx = dma_fence_context_alloc(1);
> @@ -1867,9 +1876,9 @@ void xe_vm_close_and_put(struct xe_vm *vm)
> vma = gpuva_to_vma(gpuva);
>
> if (xe_vma_has_no_bo(vma)) {
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags |= XE_VMA_DESTROYED;
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> }
>
> xe_vm_remove_vma(vm, vma);
> @@ -1913,8 +1922,7 @@ void xe_vm_close_and_put(struct xe_vm *vm)
> xe_vma_destroy_unlocked(vma);
> }
>
> - if (xe_vm_in_fault_mode(vm))
> - xe_svm_fini(vm);
> + xe_svm_fini(vm);
>
> up_write(&vm->lock);
>
> @@ -2145,9 +2153,9 @@ static const u32 region_to_mem_type[] = {
> static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
> bool post_commit)
> {
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags |= XE_VMA_DESTROYED;
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> if (post_commit)
> xe_vm_remove_vma(vm, vma);
> }
> @@ -2643,9 +2651,9 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
> struct xe_vma *vma = gpuva_to_vma(op->base.unmap.va);
>
> if (vma) {
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags &= ~XE_VMA_DESTROYED;
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> if (post_commit)
> xe_vm_insert_vma(vm, vma);
> }
> @@ -2664,9 +2672,9 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
> xe_vma_destroy_unlocked(op->remap.next);
> }
> if (vma) {
> - down_read(&vm->userptr.notifier_lock);
> + down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags &= ~XE_VMA_DESTROYED;
> - up_read(&vm->userptr.notifier_lock);
> + up_read(&vm->svm.gpusvm.notifier_lock);
> if (post_commit)
> xe_vm_insert_vma(vm, vma);
> }
> @@ -3648,7 +3656,7 @@ int xe_vm_invalidate_vma(struct xe_vma *vma)
> if (xe_vma_is_userptr(vma)) {
> WARN_ON_ONCE(!mmu_interval_check_retry
> (&to_userptr_vma(vma)->userptr.notifier,
> - to_userptr_vma(vma)->userptr.notifier_seq));
> + to_userptr_vma(vma)->userptr.pages.notifier_seq));
> WARN_ON_ONCE(!dma_resv_test_signaled(xe_vm_resv(xe_vma_vm(vma)),
> DMA_RESV_USAGE_BOOKKEEP));
>
> diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
> index 1662604c4486..b57c4299875a 100644
> --- a/drivers/gpu/drm/xe/xe_vm_types.h
> +++ b/drivers/gpu/drm/xe/xe_vm_types.h
> @@ -52,26 +52,21 @@ struct xe_userptr {
> struct list_head invalidate_link;
> /** @userptr: link into VM repin list if userptr. */
> struct list_head repin_link;
> + /**
> + * @pages: gpusvm pages for this user pointer.
> + */
> + struct drm_gpusvm_pages pages;
> /**
> * @notifier: MMU notifier for user pointer (invalidation call back)
> */
> struct mmu_interval_notifier notifier;
> - /** @sgt: storage for a scatter gather table */
> - struct sg_table sgt;
> - /** @sg: allocated scatter gather table */
> - struct sg_table *sg;
> - /** @notifier_seq: notifier sequence number */
> - unsigned long notifier_seq;
> - /** @unmap_mutex: Mutex protecting dma-unmapping */
> - struct mutex unmap_mutex;
> +
> /**
> * @initial_bind: user pointer has been bound at least once.
> - * write: vm->userptr.notifier_lock in read mode and vm->resv held.
> - * read: vm->userptr.notifier_lock in write mode or vm->resv held.
> + * write: vm->svm.gpusvm.notifier_lock in read mode and vm->resv held.
> + * read: vm->svm.gpusvm.notifier_lock in write mode or vm->resv held.
> */
> bool initial_bind;
> - /** @mapped: Whether the @sgt sg-table is dma-mapped. Protected by @unmap_mutex. */
> - bool mapped;
> #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT)
> u32 divisor;
> #endif
> @@ -109,7 +104,7 @@ struct xe_vma {
> /**
> * @tile_present: GT mask of binding are present for this VMA.
> * protected by vm->lock, vm->resv and for userptrs,
> - * vm->userptr.notifier_lock for writing. Needs either for reading,
> + * vm->svm.gpusvm.notifier_lock for writing. Needs either for reading,
> * but if reading is done under the vm->lock only, it needs to be held
> * in write mode.
> */
> @@ -243,11 +238,6 @@ struct xe_vm {
> * and needs repinning. Protected by @lock.
> */
> struct list_head repin_list;
> - /**
> - * @notifier_lock: protects notifier in write mode and
> - * submission in read mode.
> - */
> - struct rw_semaphore notifier_lock;
> /**
> * @userptr.invalidated_lock: Protects the
> * @userptr.invalidated list.
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr
2025-04-24 12:18 ` [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr Matthew Auld
2025-04-24 15:43 ` kernel test robot
@ 2025-04-24 23:18 ` Matthew Brost
1 sibling, 0 replies; 18+ messages in thread
From: Matthew Brost @ 2025-04-24 23:18 UTC (permalink / raw)
To: Matthew Auld
Cc: intel-xe, dri-devel, Himal Prasad Ghimiray, Thomas Hellström
On Thu, Apr 24, 2025 at 01:18:35PM +0100, Matthew Auld wrote:
> We now use the same notifier lock for SVM and userptr, with that we can
> combine xe_pt_userptr_pre_commit and xe_pt_svm_pre_commit.
>
> v2: (Matt B)
> - Re-use xe_svm_notifier_lock/unlock for userptr.
> - Combine svm/userptr handling further down into op_check_svm_userptr.
>
> Suggested-by: Matthew Brost <matthew.brost@intel.com>
The Kconfig issues pointed out in the previous patch need to be fixed
but implementation here look correct:
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
> Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> ---
> drivers/gpu/drm/xe/xe_pt.c | 90 ++++++++++----------------------
> drivers/gpu/drm/xe/xe_pt_types.h | 2 -
> drivers/gpu/drm/xe/xe_svm.h | 19 +++----
> 3 files changed, 39 insertions(+), 72 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
> index ff898e518afd..a7db65f9913e 100644
> --- a/drivers/gpu/drm/xe/xe_pt.c
> +++ b/drivers/gpu/drm/xe/xe_pt.c
> @@ -1393,8 +1393,8 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
> return 0;
> }
>
> -static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
> - struct xe_vm_pgtable_update_ops *pt_update)
> +static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op,
> + struct xe_vm_pgtable_update_ops *pt_update)
> {
> int err = 0;
>
> @@ -1419,6 +1419,24 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
> err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va),
> pt_update);
> break;
> +#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
> + case DRM_GPUVA_OP_DRIVER:
> + if (op->subop == XE_VMA_SUBOP_MAP_RANGE) {
> + struct xe_svm_range *range = op->map_range.range;
> +
> + xe_svm_range_debug(range, "PRE-COMMIT");
> +
> + xe_assert(vm->xe,
> + xe_vma_is_cpu_addr_mirror(op->map_range.vma));
> + xe_assert(vm->xe, op->subop == XE_VMA_SUBOP_MAP_RANGE);
> +
> + if (!xe_svm_range_pages_valid(range)) {
> + xe_svm_range_debug(range, "PRE-COMMIT - RETRY");
> + err = -EAGAIN;
> + }
> + }
> + break;
> +#endif
> default:
> drm_warn(&vm->xe->drm, "NOT POSSIBLE");
> }
> @@ -1426,7 +1444,7 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
> return err;
> }
>
> -static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
> +static int xe_pt_svm_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
> {
> struct xe_vm *vm = pt_update->vops->vm;
> struct xe_vma_ops *vops = pt_update->vops;
> @@ -1439,12 +1457,12 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
> if (err)
> return err;
>
> - down_read(&vm->svm.gpusvm.notifier_lock);
> + xe_svm_notifier_lock(vm);
>
> list_for_each_entry(op, &vops->list, link) {
> - err = op_check_userptr(vm, op, pt_update_ops);
> + err = op_check_svm_userptr(vm, op, pt_update_ops);
> if (err) {
> - up_read(&vm->svm.gpusvm.notifier_lock);
> + xe_svm_notifier_unlock(vm);
> break;
> }
> }
> @@ -1452,42 +1470,6 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
> return err;
> }
>
> -#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
> -static int xe_pt_svm_pre_commit(struct xe_migrate_pt_update *pt_update)
> -{
> - struct xe_vm *vm = pt_update->vops->vm;
> - struct xe_vma_ops *vops = pt_update->vops;
> - struct xe_vma_op *op;
> - int err;
> -
> - err = xe_pt_pre_commit(pt_update);
> - if (err)
> - return err;
> -
> - xe_svm_notifier_lock(vm);
> -
> - list_for_each_entry(op, &vops->list, link) {
> - struct xe_svm_range *range = op->map_range.range;
> -
> - if (op->subop == XE_VMA_SUBOP_UNMAP_RANGE)
> - continue;
> -
> - xe_svm_range_debug(range, "PRE-COMMIT");
> -
> - xe_assert(vm->xe, xe_vma_is_cpu_addr_mirror(op->map_range.vma));
> - xe_assert(vm->xe, op->subop == XE_VMA_SUBOP_MAP_RANGE);
> -
> - if (!xe_svm_range_pages_valid(range)) {
> - xe_svm_range_debug(range, "PRE-COMMIT - RETRY");
> - xe_svm_notifier_unlock(vm);
> - return -EAGAIN;
> - }
> - }
> -
> - return 0;
> -}
> -#endif
> -
> struct invalidation_fence {
> struct xe_gt_tlb_invalidation_fence base;
> struct xe_gt *gt;
> @@ -1858,7 +1840,7 @@ static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile,
> xe_vma_start(vma),
> xe_vma_end(vma));
> ++pt_update_ops->current_op;
> - pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma);
> + pt_update_ops->needs_svm_lock |= xe_vma_is_userptr(vma);
>
> /*
> * If rebind, we have to invalidate TLB on !LR vms to invalidate
> @@ -1966,7 +1948,7 @@ static int unbind_op_prepare(struct xe_tile *tile,
> xe_pt_update_ops_rfence_interval(pt_update_ops, xe_vma_start(vma),
> xe_vma_end(vma));
> ++pt_update_ops->current_op;
> - pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma);
> + pt_update_ops->needs_svm_lock |= xe_vma_is_userptr(vma);
> pt_update_ops->needs_invalidation = true;
>
> xe_pt_commit_prepare_unbind(vma, pt_op->entries, pt_op->num_entries);
> @@ -2289,22 +2271,12 @@ static const struct xe_migrate_pt_update_ops migrate_ops = {
> .pre_commit = xe_pt_pre_commit,
> };
>
> -static const struct xe_migrate_pt_update_ops userptr_migrate_ops = {
> +static const struct xe_migrate_pt_update_ops svm_userptr_migrate_ops = {
> .populate = xe_vm_populate_pgtable,
> .clear = xe_migrate_clear_pgtable_callback,
> - .pre_commit = xe_pt_userptr_pre_commit,
> + .pre_commit = xe_pt_svm_userptr_pre_commit,
> };
>
> -#if IS_ENABLED(CONFIG_DRM_XE_GPUSVM)
> -static const struct xe_migrate_pt_update_ops svm_migrate_ops = {
> - .populate = xe_vm_populate_pgtable,
> - .clear = xe_migrate_clear_pgtable_callback,
> - .pre_commit = xe_pt_svm_pre_commit,
> -};
> -#else
> -static const struct xe_migrate_pt_update_ops svm_migrate_ops;
> -#endif
> -
> /**
> * xe_pt_update_ops_run() - Run PT update operations
> * @tile: Tile of PT update operations
> @@ -2331,9 +2303,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
> int err = 0, i;
> struct xe_migrate_pt_update update = {
> .ops = pt_update_ops->needs_svm_lock ?
> - &svm_migrate_ops :
> - pt_update_ops->needs_userptr_lock ?
> - &userptr_migrate_ops :
> + &svm_userptr_migrate_ops :
> &migrate_ops,
> .vops = vops,
> .tile_id = tile->id,
> @@ -2455,8 +2425,6 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
>
> if (pt_update_ops->needs_svm_lock)
> xe_svm_notifier_unlock(vm);
> - if (pt_update_ops->needs_userptr_lock)
> - up_read(&vm->svm.gpusvm.notifier_lock);
>
> return fence;
>
> diff --git a/drivers/gpu/drm/xe/xe_pt_types.h b/drivers/gpu/drm/xe/xe_pt_types.h
> index 69eab6f37cfe..dc0b2d8c3af8 100644
> --- a/drivers/gpu/drm/xe/xe_pt_types.h
> +++ b/drivers/gpu/drm/xe/xe_pt_types.h
> @@ -106,8 +106,6 @@ struct xe_vm_pgtable_update_ops {
> u32 current_op;
> /** @needs_svm_lock: Needs SVM lock */
> bool needs_svm_lock;
> - /** @needs_userptr_lock: Needs userptr lock */
> - bool needs_userptr_lock;
> /** @needs_invalidation: Needs invalidation */
> bool needs_invalidation;
> /**
> diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
> index 923cb074d0cb..696496b52465 100644
> --- a/drivers/gpu/drm/xe/xe_svm.h
> +++ b/drivers/gpu/drm/xe/xe_svm.h
> @@ -87,15 +87,6 @@ static inline bool xe_svm_range_has_dma_mapping(struct xe_svm_range *range)
> return range->base.pages.flags.has_dma_mapping;
> }
>
> -#define xe_svm_assert_in_notifier(vm__) \
> - lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock)
> -
> -#define xe_svm_notifier_lock(vm__) \
> - drm_gpusvm_notifier_lock(&(vm__)->svm.gpusvm)
> -
> -#define xe_svm_notifier_unlock(vm__) \
> - drm_gpusvm_notifier_unlock(&(vm__)->svm.gpusvm)
> -
> #else
> #include <linux/interval_tree.h>
>
> @@ -187,4 +178,14 @@ static inline void xe_svm_notifier_unlock(struct xe_vm *vm)
> {
> }
> #endif
> +
> +#define xe_svm_assert_in_notifier(vm__) \
> + lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock)
> +
> +#define xe_svm_notifier_lock(vm__) \
> + drm_gpusvm_notifier_lock(&(vm__)->svm.gpusvm)
> +
> +#define xe_svm_notifier_unlock(vm__) \
> + drm_gpusvm_notifier_unlock(&(vm__)->svm.gpusvm)
> +
> #endif
> --
> 2.49.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
` (2 preceding siblings ...)
2025-04-24 23:17 ` Matthew Brost
@ 2025-04-25 14:00 ` kernel test robot
2025-04-28 3:47 ` Dafna Hirschfeld
4 siblings, 0 replies; 18+ messages in thread
From: kernel test robot @ 2025-04-25 14:00 UTC (permalink / raw)
To: Matthew Auld, intel-xe
Cc: Paul Gazzillo, Necip Fazil Yildiran, oe-kbuild-all, dri-devel,
Himal Prasad Ghimiray, Thomas Hellström, Matthew Brost
Hi Matthew,
kernel test robot noticed the following build warnings:
[auto build test WARNING on drm-xe/drm-xe-next]
[also build test WARNING on next-20250424]
[cannot apply to drm-exynos/exynos-drm-next linus/master drm/drm-next drm-intel/for-linux-next drm-intel/for-linux-next-fixes drm-misc/drm-misc-next drm-tip/drm-tip v6.15-rc3]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Auld/drm-gpusvm-fix-hmm_pfn_to_map_order-usage/20250424-202128
base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next
patch link: https://lore.kernel.org/r/20250424121827.862729-15-matthew.auld%40intel.com
patch subject: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
config: alpha-kismet-CONFIG_DRM_GPUSVM-CONFIG_DRM_XE-0-0 (https://download.01.org/0day-ci/archive/20250425/202504252124.jQDkibSg-lkp@intel.com/config)
reproduce: (https://download.01.org/0day-ci/archive/20250425/202504252124.jQDkibSg-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202504252124.jQDkibSg-lkp@intel.com/
kismet warnings: (new ones prefixed by >>)
>> kismet: WARNING: unmet direct dependencies detected for DRM_GPUSVM when selected by DRM_XE
WARNING: unmet direct dependencies detected for LEDS_EXPRESSWIRE
Depends on [n]: GPIOLIB [=n] || NEW_LEDS [=y] && GPIOLIB [=n]
Selected by [y]:
- BACKLIGHT_KTD2801 [=y] && HAS_IOMEM [=y] && BACKLIGHT_CLASS_DEVICE [=y]
WARNING: unmet direct dependencies detected for DRM_GPUSVM
Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DEVICE_PRIVATE [=n]
Selected by [m]:
- DRM_XE [=m] && HAS_IOMEM [=y] && DRM [=y] && PCI [=y] && MMU [=y] && (m [=m] && MODULES [=y] || KUNIT [=n]=y [=y])
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
` (3 preceding siblings ...)
2025-04-25 14:00 ` kernel test robot
@ 2025-04-28 3:47 ` Dafna Hirschfeld
4 siblings, 0 replies; 18+ messages in thread
From: Dafna Hirschfeld @ 2025-04-28 3:47 UTC (permalink / raw)
To: Matthew Auld
Cc: intel-xe, dri-devel, Himal Prasad Ghimiray, Thomas Hellström,
Matthew Brost
On 24.04.2025 13:18, Matthew Auld wrote:
>Goal here is cut over to gpusvm and remove xe_hmm, relying instead on
>common code. The core facilities we need are get_pages(), unmap_pages()
>and free_pages() for a given useptr range, plus a vm level notifier
>lock, which is now provided by gpusvm.
>
>v2:
> - Reuse the same SVM vm struct we use for full SVM, that way we can
> use the same lock (Matt B & Himal)
>v3:
> - Re-use svm_init/fini for userptr.
>
>Signed-off-by: Matthew Auld <matthew.auld@intel.com>
>Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
>Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>Cc: Matthew Brost <matthew.brost@intel.com>
>---
> drivers/gpu/drm/xe/Kconfig | 3 +-
> drivers/gpu/drm/xe/Makefile | 1 -
> drivers/gpu/drm/xe/xe_exec.c | 4 +-
> drivers/gpu/drm/xe/xe_hmm.c | 325 -------------------------------
> drivers/gpu/drm/xe/xe_hmm.h | 18 --
> drivers/gpu/drm/xe/xe_pt.c | 22 +--
> drivers/gpu/drm/xe/xe_svm.c | 32 +--
> drivers/gpu/drm/xe/xe_svm.h | 6 +-
> drivers/gpu/drm/xe/xe_vm.c | 86 ++++----
> drivers/gpu/drm/xe/xe_vm_types.h | 26 +--
> 10 files changed, 92 insertions(+), 431 deletions(-)
> delete mode 100644 drivers/gpu/drm/xe/xe_hmm.c
> delete mode 100644 drivers/gpu/drm/xe/xe_hmm.h
>
>diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
>index 9bce047901b2..1e63dde76c55 100644
>--- a/drivers/gpu/drm/xe/Kconfig
>+++ b/drivers/gpu/drm/xe/Kconfig
>@@ -43,7 +43,7 @@ config DRM_XE
> select MMU_NOTIFIER
> select WANT_DEV_COREDUMP
> select AUXILIARY_BUS
>- select HMM_MIRROR
>+ select DRM_GPUSVM
> help
> Experimental driver for Intel Xe series GPUs
>
>@@ -79,7 +79,6 @@ config DRM_XE_GPUSVM
> depends on !UML
> depends on DEVICE_PRIVATE
> default y
>- select DRM_GPUSVM
> help
> Enable this option if you want support for CPU to GPU address
> mirroring.
>diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
>index 3ecac0a38b82..f1123be158f8 100644
>--- a/drivers/gpu/drm/xe/Makefile
>+++ b/drivers/gpu/drm/xe/Makefile
>@@ -124,7 +124,6 @@ xe-y += xe_bb.o \
> xe_wait_user_fence.o \
> xe_wopcm.o
>
>-xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o
> xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
>
> # graphics hardware monitoring (HWMON) support
>diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c
>index b75adfc99fb7..c0ce681076d5 100644
>--- a/drivers/gpu/drm/xe/xe_exec.c
>+++ b/drivers/gpu/drm/xe/xe_exec.c
>@@ -294,7 +294,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
> if (err)
> goto err_put_job;
>
>- err = down_read_interruptible(&vm->userptr.notifier_lock);
>+ err = down_read_interruptible(&vm->svm.gpusvm.notifier_lock);
> if (err)
> goto err_put_job;
>
>@@ -336,7 +336,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>
> err_repin:
> if (!xe_vm_in_lr_mode(vm))
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> err_put_job:
> if (err)
> xe_sched_job_put(job);
>diff --git a/drivers/gpu/drm/xe/xe_hmm.c b/drivers/gpu/drm/xe/xe_hmm.c
>deleted file mode 100644
>index 57b71956ddf4..000000000000
>--- a/drivers/gpu/drm/xe/xe_hmm.c
>+++ /dev/null
>@@ -1,325 +0,0 @@
>-// SPDX-License-Identifier: MIT
>-/*
>- * Copyright © 2024 Intel Corporation
>- */
>-
>-#include <linux/scatterlist.h>
>-#include <linux/mmu_notifier.h>
>-#include <linux/dma-mapping.h>
>-#include <linux/memremap.h>
>-#include <linux/swap.h>
>-#include <linux/hmm.h>
>-#include <linux/mm.h>
>-#include "xe_hmm.h"
>-#include "xe_vm.h"
>-#include "xe_bo.h"
>-
>-static u64 xe_npages_in_range(unsigned long start, unsigned long end)
>-{
>- return (end - start) >> PAGE_SHIFT;
>-}
>-
>-static int xe_alloc_sg(struct xe_device *xe, struct sg_table *st,
>- struct hmm_range *range, struct rw_semaphore *notifier_sem)
>-{
>- unsigned long i, npages, hmm_pfn;
>- unsigned long num_chunks = 0;
>- int ret;
>-
>- /* HMM docs says this is needed. */
>- ret = down_read_interruptible(notifier_sem);
>- if (ret)
>- return ret;
>-
>- if (mmu_interval_read_retry(range->notifier, range->notifier_seq)) {
>- up_read(notifier_sem);
>- return -EAGAIN;
>- }
>-
>- npages = xe_npages_in_range(range->start, range->end);
>- for (i = 0; i < npages;) {
>- unsigned long len;
>-
>- hmm_pfn = range->hmm_pfns[i];
>- xe_assert(xe, hmm_pfn & HMM_PFN_VALID);
>-
>- len = 1UL << hmm_pfn_to_map_order(hmm_pfn);
>-
>- /* If order > 0 the page may extend beyond range->start */
>- len -= (hmm_pfn & ~HMM_PFN_FLAGS) & (len - 1);
>- i += len;
>- num_chunks++;
>- }
>- up_read(notifier_sem);
>-
>- return sg_alloc_table(st, num_chunks, GFP_KERNEL);
>-}
>-
>-/**
>- * xe_build_sg() - build a scatter gather table for all the physical pages/pfn
>- * in a hmm_range. dma-map pages if necessary. dma-address is save in sg table
>- * and will be used to program GPU page table later.
>- * @xe: the xe device who will access the dma-address in sg table
>- * @range: the hmm range that we build the sg table from. range->hmm_pfns[]
>- * has the pfn numbers of pages that back up this hmm address range.
>- * @st: pointer to the sg table.
>- * @notifier_sem: The xe notifier lock.
>- * @write: whether we write to this range. This decides dma map direction
>- * for system pages. If write we map it bi-diretional; otherwise
>- * DMA_TO_DEVICE
>- *
>- * All the contiguous pfns will be collapsed into one entry in
>- * the scatter gather table. This is for the purpose of efficiently
>- * programming GPU page table.
>- *
>- * The dma_address in the sg table will later be used by GPU to
>- * access memory. So if the memory is system memory, we need to
>- * do a dma-mapping so it can be accessed by GPU/DMA.
>- *
>- * FIXME: This function currently only support pages in system
>- * memory. If the memory is GPU local memory (of the GPU who
>- * is going to access memory), we need gpu dpa (device physical
>- * address), and there is no need of dma-mapping. This is TBD.
>- *
>- * FIXME: dma-mapping for peer gpu device to access remote gpu's
>- * memory. Add this when you support p2p
>- *
>- * This function allocates the storage of the sg table. It is
>- * caller's responsibility to free it calling sg_free_table.
>- *
>- * Returns 0 if successful; -ENOMEM if fails to allocate memory
>- */
>-static int xe_build_sg(struct xe_device *xe, struct hmm_range *range,
>- struct sg_table *st,
>- struct rw_semaphore *notifier_sem,
>- bool write)
>-{
>- unsigned long npages = xe_npages_in_range(range->start, range->end);
>- struct device *dev = xe->drm.dev;
>- struct scatterlist *sgl;
>- struct page *page;
>- unsigned long i, j;
>-
>- lockdep_assert_held(notifier_sem);
>-
>- i = 0;
>- for_each_sg(st->sgl, sgl, st->nents, j) {
>- unsigned long hmm_pfn, size;
>-
>- hmm_pfn = range->hmm_pfns[i];
>- page = hmm_pfn_to_page(hmm_pfn);
>- xe_assert(xe, !is_device_private_page(page));
>-
>- size = 1UL << hmm_pfn_to_map_order(hmm_pfn);
>- size -= page_to_pfn(page) & (size - 1);
>- i += size;
>-
>- if (unlikely(j == st->nents - 1)) {
>- xe_assert(xe, i >= npages);
>- if (i > npages)
>- size -= (i - npages);
>-
>- sg_mark_end(sgl);
>- } else {
>- xe_assert(xe, i < npages);
>- }
>-
>- sg_set_page(sgl, page, size << PAGE_SHIFT, 0);
>- }
>-
>- return dma_map_sgtable(dev, st, write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE,
>- DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_NO_KERNEL_MAPPING);
>-}
>-
>-static void xe_hmm_userptr_set_mapped(struct xe_userptr_vma *uvma)
>-{
>- struct xe_userptr *userptr = &uvma->userptr;
>- struct xe_vm *vm = xe_vma_vm(&uvma->vma);
>-
>- lockdep_assert_held_write(&vm->lock);
>- lockdep_assert_held(&vm->userptr.notifier_lock);
>-
>- mutex_lock(&userptr->unmap_mutex);
>- xe_assert(vm->xe, !userptr->mapped);
>- userptr->mapped = true;
>- mutex_unlock(&userptr->unmap_mutex);
>-}
>-
>-void xe_hmm_userptr_unmap(struct xe_userptr_vma *uvma)
>-{
>- struct xe_userptr *userptr = &uvma->userptr;
>- struct xe_vma *vma = &uvma->vma;
>- bool write = !xe_vma_read_only(vma);
>- struct xe_vm *vm = xe_vma_vm(vma);
>- struct xe_device *xe = vm->xe;
>-
>- if (!lockdep_is_held_type(&vm->userptr.notifier_lock, 0) &&
>- !lockdep_is_held_type(&vm->lock, 0) &&
>- !(vma->gpuva.flags & XE_VMA_DESTROYED)) {
>- /* Don't unmap in exec critical section. */
>- xe_vm_assert_held(vm);
>- /* Don't unmap while mapping the sg. */
>- lockdep_assert_held(&vm->lock);
>- }
>-
>- mutex_lock(&userptr->unmap_mutex);
>- if (userptr->sg && userptr->mapped)
>- dma_unmap_sgtable(xe->drm.dev, userptr->sg,
>- write ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE, 0);
>- userptr->mapped = false;
>- mutex_unlock(&userptr->unmap_mutex);
>-}
>-
>-/**
>- * xe_hmm_userptr_free_sg() - Free the scatter gather table of userptr
>- * @uvma: the userptr vma which hold the scatter gather table
>- *
>- * With function xe_userptr_populate_range, we allocate storage of
>- * the userptr sg table. This is a helper function to free this
>- * sg table, and dma unmap the address in the table.
>- */
>-void xe_hmm_userptr_free_sg(struct xe_userptr_vma *uvma)
>-{
>- struct xe_userptr *userptr = &uvma->userptr;
>-
>- xe_assert(xe_vma_vm(&uvma->vma)->xe, userptr->sg);
>- xe_hmm_userptr_unmap(uvma);
>- sg_free_table(userptr->sg);
>- userptr->sg = NULL;
>-}
>-
>-/**
>- * xe_hmm_userptr_populate_range() - Populate physical pages of a virtual
>- * address range
>- *
>- * @uvma: userptr vma which has information of the range to populate.
>- * @is_mm_mmap_locked: True if mmap_read_lock is already acquired by caller.
>- *
>- * This function populate the physical pages of a virtual
>- * address range. The populated physical pages is saved in
>- * userptr's sg table. It is similar to get_user_pages but call
>- * hmm_range_fault.
>- *
>- * This function also read mmu notifier sequence # (
>- * mmu_interval_read_begin), for the purpose of later
>- * comparison (through mmu_interval_read_retry).
>- *
>- * This must be called with mmap read or write lock held.
>- *
>- * This function allocates the storage of the userptr sg table.
>- * It is caller's responsibility to free it calling sg_free_table.
>- *
>- * returns: 0 for success; negative error no on failure
>- */
>-int xe_hmm_userptr_populate_range(struct xe_userptr_vma *uvma,
>- bool is_mm_mmap_locked)
>-{
>- unsigned long timeout =
>- jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
>- unsigned long *pfns;
>- struct xe_userptr *userptr;
>- struct xe_vma *vma = &uvma->vma;
>- u64 userptr_start = xe_vma_userptr(vma);
>- u64 userptr_end = userptr_start + xe_vma_size(vma);
>- struct xe_vm *vm = xe_vma_vm(vma);
>- struct hmm_range hmm_range = {
>- .pfn_flags_mask = 0, /* ignore pfns */
>- .default_flags = HMM_PFN_REQ_FAULT,
>- .start = userptr_start,
>- .end = userptr_end,
>- .notifier = &uvma->userptr.notifier,
>- .dev_private_owner = vm->xe,
>- };
>- bool write = !xe_vma_read_only(vma);
>- unsigned long notifier_seq;
>- u64 npages;
>- int ret;
>-
>- userptr = &uvma->userptr;
>-
>- if (is_mm_mmap_locked)
>- mmap_assert_locked(userptr->notifier.mm);
>-
>- if (vma->gpuva.flags & XE_VMA_DESTROYED)
>- return 0;
>-
>- notifier_seq = mmu_interval_read_begin(&userptr->notifier);
>- if (notifier_seq == userptr->notifier_seq)
>- return 0;
>-
>- if (userptr->sg)
>- xe_hmm_userptr_free_sg(uvma);
>-
>- npages = xe_npages_in_range(userptr_start, userptr_end);
>- pfns = kvmalloc_array(npages, sizeof(*pfns), GFP_KERNEL);
>- if (unlikely(!pfns))
>- return -ENOMEM;
>-
>- if (write)
>- hmm_range.default_flags |= HMM_PFN_REQ_WRITE;
>-
>- if (!mmget_not_zero(userptr->notifier.mm)) {
>- ret = -EFAULT;
>- goto free_pfns;
>- }
>-
>- hmm_range.hmm_pfns = pfns;
>-
>- while (true) {
>- hmm_range.notifier_seq = mmu_interval_read_begin(&userptr->notifier);
>-
>- if (!is_mm_mmap_locked)
>- mmap_read_lock(userptr->notifier.mm);
>-
>- ret = hmm_range_fault(&hmm_range);
>-
>- if (!is_mm_mmap_locked)
>- mmap_read_unlock(userptr->notifier.mm);
>-
>- if (ret == -EBUSY) {
>- if (time_after(jiffies, timeout))
>- break;
>-
>- continue;
>- }
>- break;
>- }
>-
>- mmput(userptr->notifier.mm);
>-
>- if (ret)
>- goto free_pfns;
>-
>- ret = xe_alloc_sg(vm->xe, &userptr->sgt, &hmm_range, &vm->userptr.notifier_lock);
>- if (ret)
>- goto free_pfns;
>-
>- ret = down_read_interruptible(&vm->userptr.notifier_lock);
>- if (ret)
>- goto free_st;
>-
>- if (mmu_interval_read_retry(hmm_range.notifier, hmm_range.notifier_seq)) {
>- ret = -EAGAIN;
>- goto out_unlock;
>- }
>-
>- ret = xe_build_sg(vm->xe, &hmm_range, &userptr->sgt,
>- &vm->userptr.notifier_lock, write);
>- if (ret)
>- goto out_unlock;
>-
>- userptr->sg = &userptr->sgt;
>- xe_hmm_userptr_set_mapped(uvma);
>- userptr->notifier_seq = hmm_range.notifier_seq;
>- up_read(&vm->userptr.notifier_lock);
>- kvfree(pfns);
>- return 0;
>-
>-out_unlock:
>- up_read(&vm->userptr.notifier_lock);
>-free_st:
>- sg_free_table(&userptr->sgt);
>-free_pfns:
>- kvfree(pfns);
>- return ret;
>-}
>diff --git a/drivers/gpu/drm/xe/xe_hmm.h b/drivers/gpu/drm/xe/xe_hmm.h
>deleted file mode 100644
>index 0ea98d8e7bbc..000000000000
>--- a/drivers/gpu/drm/xe/xe_hmm.h
>+++ /dev/null
>@@ -1,18 +0,0 @@
>-/* SPDX-License-Identifier: MIT
>- *
>- * Copyright © 2024 Intel Corporation
>- */
>-
>-#ifndef _XE_HMM_H_
>-#define _XE_HMM_H_
>-
>-#include <linux/types.h>
>-
>-struct xe_userptr_vma;
>-
>-int xe_hmm_userptr_populate_range(struct xe_userptr_vma *uvma, bool is_mm_mmap_locked);
>-
>-void xe_hmm_userptr_free_sg(struct xe_userptr_vma *uvma);
>-
>-void xe_hmm_userptr_unmap(struct xe_userptr_vma *uvma);
>-#endif
>diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
>index 5cccfd9cc3e9..ff898e518afd 100644
>--- a/drivers/gpu/drm/xe/xe_pt.c
>+++ b/drivers/gpu/drm/xe/xe_pt.c
>@@ -756,8 +756,8 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
>
> if (!xe_vma_is_null(vma) && !range) {
> if (xe_vma_is_userptr(vma))
>- xe_res_first_sg(to_userptr_vma(vma)->userptr.sg, 0,
>- xe_vma_size(vma), &curs);
>+ xe_res_first_dma(to_userptr_vma(vma)->userptr.pages.dma_addr, 0,
>+ xe_vma_size(vma), &curs);
> else if (xe_bo_is_vram(bo) || xe_bo_is_stolen(bo))
> xe_res_first(bo->ttm.resource, xe_vma_bo_offset(vma),
> xe_vma_size(vma), &curs);
>@@ -1028,7 +1028,7 @@ static void xe_pt_commit_locks_assert(struct xe_vma *vma)
> xe_pt_commit_prepare_locks_assert(vma);
>
> if (xe_vma_is_userptr(vma))
>- lockdep_assert_held_read(&vm->userptr.notifier_lock);
>+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
> }
>
> static void xe_pt_commit(struct xe_vma *vma,
>@@ -1368,7 +1368,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
> struct xe_userptr_vma *uvma;
> unsigned long notifier_seq;
>
>- lockdep_assert_held_read(&vm->userptr.notifier_lock);
>+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> if (!xe_vma_is_userptr(vma))
> return 0;
>@@ -1377,7 +1377,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma,
> if (xe_pt_userptr_inject_eagain(uvma))
> xe_vma_userptr_force_invalidate(uvma);
>
>- notifier_seq = uvma->userptr.notifier_seq;
>+ notifier_seq = uvma->userptr.pages.notifier_seq;
>
> if (!mmu_interval_read_retry(&uvma->userptr.notifier,
> notifier_seq))
>@@ -1398,7 +1398,7 @@ static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op,
> {
> int err = 0;
>
>- lockdep_assert_held_read(&vm->userptr.notifier_lock);
>+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> switch (op->base.op) {
> case DRM_GPUVA_OP_MAP:
>@@ -1439,12 +1439,12 @@ static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update)
> if (err)
> return err;
>
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
>
> list_for_each_entry(op, &vops->list, link) {
> err = op_check_userptr(vm, op, pt_update_ops);
> if (err) {
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> break;
> }
> }
>@@ -2171,7 +2171,7 @@ static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
> if (invalidate_on_bind)
> vma->tile_invalidated |= BIT(tile->id);
> if (xe_vma_is_userptr(vma)) {
>- lockdep_assert_held_read(&vm->userptr.notifier_lock);
>+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
> to_userptr_vma(vma)->userptr.initial_bind = true;
> }
>
>@@ -2207,7 +2207,7 @@ static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile,
> if (!vma->tile_present) {
> list_del_init(&vma->combined_links.rebind);
> if (xe_vma_is_userptr(vma)) {
>- lockdep_assert_held_read(&vm->userptr.notifier_lock);
>+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> spin_lock(&vm->userptr.invalidated_lock);
> list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link);
>@@ -2456,7 +2456,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops)
> if (pt_update_ops->needs_svm_lock)
> xe_svm_notifier_unlock(vm);
> if (pt_update_ops->needs_userptr_lock)
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
>
> return fence;
>
>diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
>index f60c7f587cd6..10ec237ec88c 100644
>--- a/drivers/gpu/drm/xe/xe_svm.c
>+++ b/drivers/gpu/drm/xe/xe_svm.c
>@@ -606,22 +606,26 @@ int xe_svm_init(struct xe_vm *vm)
> {
> int err;
>
>- spin_lock_init(&vm->svm.garbage_collector.lock);
>- INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
>- INIT_WORK(&vm->svm.garbage_collector.work,
>- xe_svm_garbage_collector_work_func);
>+ if (vm->flags & XE_VM_FLAG_FAULT_MODE) {
>+ spin_lock_init(&vm->svm.garbage_collector.lock);
>+ INIT_LIST_HEAD(&vm->svm.garbage_collector.range_list);
>+ INIT_WORK(&vm->svm.garbage_collector.work,
>+ xe_svm_garbage_collector_work_func);
>
>- err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
>- current->mm, xe_svm_devm_owner(vm->xe), 0,
>- vm->size, xe_modparam.svm_notifier_size * SZ_1M,
>- &gpusvm_ops, fault_chunk_sizes,
>- ARRAY_SIZE(fault_chunk_sizes));
>- if (err)
>- return err;
>+ err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM", &vm->xe->drm,
>+ current->mm, xe_svm_devm_owner(vm->xe), 0,
>+ vm->size,
>+ xe_modparam.svm_notifier_size * SZ_1M,
>+ &gpusvm_ops, fault_chunk_sizes,
>+ ARRAY_SIZE(fault_chunk_sizes));
>+ drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
>+ } else {
>+ err = drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)",
>+ &vm->xe->drm, NULL, NULL, 0, 0, 0, NULL,
>+ NULL, 0);
>+ }
>
>- drm_gpusvm_driver_set_lock(&vm->svm.gpusvm, &vm->lock);
>-
>- return 0;
>+ return err;
> }
>
> /**
>diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h
>index 8bc83de87250..923cb074d0cb 100644
>--- a/drivers/gpu/drm/xe/xe_svm.h
>+++ b/drivers/gpu/drm/xe/xe_svm.h
>@@ -134,12 +134,16 @@ int xe_devm_add(struct xe_tile *tile, struct xe_vram_region *vr)
> static inline
> int xe_svm_init(struct xe_vm *vm)
> {
>- return 0;
>+ return drm_gpusvm_init(&vm->svm.gpusvm, "Xe SVM (simple)", &vm->xe->drm,
>+ NULL, NULL, 0, 0, 0, NULL, NULL, 0);
> }
>
> static inline
> void xe_svm_fini(struct xe_vm *vm)
> {
>+ xe_assert(vm->xe, xe_vm_is_closed(vm));
>+
>+ drm_gpusvm_fini(&vm->svm.gpusvm);
> }
>
> static inline
>diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c
>index 0c69ef6b5ec5..b900afe61931 100644
>--- a/drivers/gpu/drm/xe/xe_vm.c
>+++ b/drivers/gpu/drm/xe/xe_vm.c
>@@ -40,7 +40,6 @@
> #include "xe_sync.h"
> #include "xe_trace_bo.h"
> #include "xe_wa.h"
>-#include "xe_hmm.h"
>
> static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> {
>@@ -53,7 +52,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> *
> * Check if the userptr vma has been invalidated since last successful
> * repin. The check is advisory only and can the function can be called
>- * without the vm->userptr.notifier_lock held. There is no guarantee that the
>+ * without the vm->svm.gpusvm.notifier_lock held. There is no guarantee that the
> * vma userptr will remain valid after a lockless check, so typically
> * the call needs to be followed by a proper check under the notifier_lock.
> *
>@@ -62,7 +61,7 @@ static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
> int xe_vma_userptr_check_repin(struct xe_userptr_vma *uvma)
> {
> return mmu_interval_check_retry(&uvma->userptr.notifier,
>- uvma->userptr.notifier_seq) ?
>+ uvma->userptr.pages.notifier_seq) ?
> -EAGAIN : 0;
> }
>
>@@ -71,11 +70,22 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma)
> struct xe_vma *vma = &uvma->vma;
> struct xe_vm *vm = xe_vma_vm(vma);
> struct xe_device *xe = vm->xe;
>+ struct drm_gpusvm_ctx ctx = {
>+ .read_only = xe_vma_read_only(vma),
>+ };
>
> lockdep_assert_held(&vm->lock);
> xe_assert(xe, xe_vma_is_userptr(vma));
>
>- return xe_hmm_userptr_populate_range(uvma, false);
>+ if (vma->gpuva.flags & XE_VMA_DESTROYED)
>+ return 0;
>+
>+ return drm_gpusvm_get_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
>+ uvma->userptr.notifier.mm,
>+ &uvma->userptr.notifier,
>+ xe_vma_userptr(vma),
>+ xe_vma_userptr(vma) + xe_vma_size(vma),
>+ &ctx);
> }
>
> static bool preempt_fences_waiting(struct xe_vm *vm)
>@@ -249,7 +259,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
> ++vm->preempt.num_exec_queues;
> q->lr.pfence = pfence;
>
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
>
> drm_gpuvm_resv_add_fence(&vm->gpuvm, exec, pfence,
> DMA_RESV_USAGE_BOOKKEEP, DMA_RESV_USAGE_BOOKKEEP);
>@@ -263,7 +273,7 @@ int xe_vm_add_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
> if (wait)
> dma_fence_enable_sw_signaling(pfence);
>
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
>
> out_fini:
> drm_exec_fini(exec);
>@@ -305,14 +315,14 @@ void xe_vm_remove_compute_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q)
> * @vm: The VM.
> *
> * This function checks for whether the VM has userptrs that need repinning,
>- * and provides a release-type barrier on the userptr.notifier_lock after
>+ * and provides a release-type barrier on the svm.gpusvm.notifier_lock after
> * checking.
> *
> * Return: 0 if there are no userptrs needing repinning, -EAGAIN if there are.
> */
> int __xe_vm_userptr_needs_repin(struct xe_vm *vm)
> {
>- lockdep_assert_held_read(&vm->userptr.notifier_lock);
>+ lockdep_assert_held_read(&vm->svm.gpusvm.notifier_lock);
>
> return (list_empty(&vm->userptr.repin_list) &&
> list_empty(&vm->userptr.invalidated)) ? 0 : -EAGAIN;
>@@ -546,9 +556,9 @@ static void preempt_rebind_work_func(struct work_struct *w)
> (!(__tries)++ || __xe_vm_userptr_needs_repin(__vm)) : \
> __xe_vm_userptr_needs_repin(__vm))
>
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
> if (retry_required(tries, vm)) {
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> err = -EAGAIN;
> goto out_unlock;
> }
>@@ -562,7 +572,7 @@ static void preempt_rebind_work_func(struct work_struct *w)
> /* Point of no return. */
> arm_preempt_fences(vm, &preempt_fences);
> resume_and_reinstall_preempt_fences(vm, &exec);
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
>
> out_unlock:
> drm_exec_fini(&exec);
>@@ -589,6 +599,9 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv
> struct xe_vma *vma = &uvma->vma;
> struct dma_resv_iter cursor;
> struct dma_fence *fence;
>+ struct drm_gpusvm_ctx ctx = {
>+ .in_notifier = true,
better to also add:
.read_only = xe_vma_read_only(vma),
thanks,
Dafna
>+ };
> long err;
>
> /*
>@@ -625,7 +638,8 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv
> XE_WARN_ON(err);
> }
>
>- xe_hmm_userptr_unmap(uvma);
>+ drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
>+ xe_vma_size(vma) >> PAGE_SHIFT, &ctx);
> }
>
> static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
>@@ -646,11 +660,11 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni,
> "NOTIFIER: addr=0x%016llx, range=0x%016llx",
> xe_vma_start(vma), xe_vma_size(vma));
>
>- down_write(&vm->userptr.notifier_lock);
>+ down_write(&vm->svm.gpusvm.notifier_lock);
> mmu_interval_set_seq(mni, cur_seq);
>
> __vma_userptr_invalidate(vm, uvma);
>- up_write(&vm->userptr.notifier_lock);
>+ up_write(&vm->svm.gpusvm.notifier_lock);
> trace_xe_vma_userptr_invalidate_complete(vma);
>
> return true;
>@@ -674,7 +688,7 @@ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma)
> /* Protect against concurrent userptr pinning */
> lockdep_assert_held(&vm->lock);
> /* Protect against concurrent notifiers */
>- lockdep_assert_held(&vm->userptr.notifier_lock);
>+ lockdep_assert_held(&vm->svm.gpusvm.notifier_lock);
> /*
> * Protect against concurrent instances of this function and
> * the critical exec sections
>@@ -747,7 +761,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
> }
>
> if (err) {
>- down_write(&vm->userptr.notifier_lock);
>+ down_write(&vm->svm.gpusvm.notifier_lock);
> spin_lock(&vm->userptr.invalidated_lock);
> list_for_each_entry_safe(uvma, next, &vm->userptr.repin_list,
> userptr.repin_link) {
>@@ -756,7 +770,7 @@ int xe_vm_userptr_pin(struct xe_vm *vm)
> &vm->userptr.invalidated);
> }
> spin_unlock(&vm->userptr.invalidated_lock);
>- up_write(&vm->userptr.notifier_lock);
>+ up_write(&vm->svm.gpusvm.notifier_lock);
> }
> return err;
> }
>@@ -1222,7 +1236,6 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
> INIT_LIST_HEAD(&userptr->invalidate_link);
> INIT_LIST_HEAD(&userptr->repin_link);
> vma->gpuva.gem.offset = bo_offset_or_userptr;
>- mutex_init(&userptr->unmap_mutex);
>
> err = mmu_interval_notifier_insert(&userptr->notifier,
> current->mm,
>@@ -1233,7 +1246,7 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm,
> return ERR_PTR(err);
> }
>
>- userptr->notifier_seq = LONG_MAX;
>+ userptr->pages.notifier_seq = LONG_MAX;
> }
>
> xe_vm_get(vm);
>@@ -1255,8 +1268,8 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
> struct xe_userptr_vma *uvma = to_userptr_vma(vma);
> struct xe_userptr *userptr = &uvma->userptr;
>
>- if (userptr->sg)
>- xe_hmm_userptr_free_sg(uvma);
>+ drm_gpusvm_free_pages(&vm->svm.gpusvm, &uvma->userptr.pages,
>+ xe_vma_size(vma) >> PAGE_SHIFT);
>
> /*
> * Since userptr pages are not pinned, we can't remove
>@@ -1264,7 +1277,6 @@ static void xe_vma_destroy_late(struct xe_vma *vma)
> * them anymore
> */
> mmu_interval_notifier_remove(&userptr->notifier);
>- mutex_destroy(&userptr->unmap_mutex);
> xe_vm_put(vm);
> } else if (xe_vma_is_null(vma) || xe_vma_is_cpu_addr_mirror(vma)) {
> xe_vm_put(vm);
>@@ -1657,7 +1669,6 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
>
> INIT_LIST_HEAD(&vm->userptr.repin_list);
> INIT_LIST_HEAD(&vm->userptr.invalidated);
>- init_rwsem(&vm->userptr.notifier_lock);
> spin_lock_init(&vm->userptr.invalidated_lock);
>
> ttm_lru_bulk_move_init(&vm->lru_bulk_move);
>@@ -1757,11 +1768,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags)
> }
> }
>
>- if (flags & XE_VM_FLAG_FAULT_MODE) {
>- err = xe_svm_init(vm);
>- if (err)
>- goto err_close;
>- }
>+ err = xe_svm_init(vm);
>+ if (err)
>+ goto err_close;
>
> if (number_tiles > 1)
> vm->composite_fence_ctx = dma_fence_context_alloc(1);
>@@ -1867,9 +1876,9 @@ void xe_vm_close_and_put(struct xe_vm *vm)
> vma = gpuva_to_vma(gpuva);
>
> if (xe_vma_has_no_bo(vma)) {
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags |= XE_VMA_DESTROYED;
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> }
>
> xe_vm_remove_vma(vm, vma);
>@@ -1913,8 +1922,7 @@ void xe_vm_close_and_put(struct xe_vm *vm)
> xe_vma_destroy_unlocked(vma);
> }
>
>- if (xe_vm_in_fault_mode(vm))
>- xe_svm_fini(vm);
>+ xe_svm_fini(vm);
>
> up_write(&vm->lock);
>
>@@ -2145,9 +2153,9 @@ static const u32 region_to_mem_type[] = {
> static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma,
> bool post_commit)
> {
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags |= XE_VMA_DESTROYED;
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> if (post_commit)
> xe_vm_remove_vma(vm, vma);
> }
>@@ -2643,9 +2651,9 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
> struct xe_vma *vma = gpuva_to_vma(op->base.unmap.va);
>
> if (vma) {
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags &= ~XE_VMA_DESTROYED;
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> if (post_commit)
> xe_vm_insert_vma(vm, vma);
> }
>@@ -2664,9 +2672,9 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op,
> xe_vma_destroy_unlocked(op->remap.next);
> }
> if (vma) {
>- down_read(&vm->userptr.notifier_lock);
>+ down_read(&vm->svm.gpusvm.notifier_lock);
> vma->gpuva.flags &= ~XE_VMA_DESTROYED;
>- up_read(&vm->userptr.notifier_lock);
>+ up_read(&vm->svm.gpusvm.notifier_lock);
> if (post_commit)
> xe_vm_insert_vma(vm, vma);
> }
>@@ -3648,7 +3656,7 @@ int xe_vm_invalidate_vma(struct xe_vma *vma)
> if (xe_vma_is_userptr(vma)) {
> WARN_ON_ONCE(!mmu_interval_check_retry
> (&to_userptr_vma(vma)->userptr.notifier,
>- to_userptr_vma(vma)->userptr.notifier_seq));
>+ to_userptr_vma(vma)->userptr.pages.notifier_seq));
> WARN_ON_ONCE(!dma_resv_test_signaled(xe_vm_resv(xe_vma_vm(vma)),
> DMA_RESV_USAGE_BOOKKEEP));
>
>diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
>index 1662604c4486..b57c4299875a 100644
>--- a/drivers/gpu/drm/xe/xe_vm_types.h
>+++ b/drivers/gpu/drm/xe/xe_vm_types.h
>@@ -52,26 +52,21 @@ struct xe_userptr {
> struct list_head invalidate_link;
> /** @userptr: link into VM repin list if userptr. */
> struct list_head repin_link;
>+ /**
>+ * @pages: gpusvm pages for this user pointer.
>+ */
>+ struct drm_gpusvm_pages pages;
> /**
> * @notifier: MMU notifier for user pointer (invalidation call back)
> */
> struct mmu_interval_notifier notifier;
>- /** @sgt: storage for a scatter gather table */
>- struct sg_table sgt;
>- /** @sg: allocated scatter gather table */
>- struct sg_table *sg;
>- /** @notifier_seq: notifier sequence number */
>- unsigned long notifier_seq;
>- /** @unmap_mutex: Mutex protecting dma-unmapping */
>- struct mutex unmap_mutex;
>+
> /**
> * @initial_bind: user pointer has been bound at least once.
>- * write: vm->userptr.notifier_lock in read mode and vm->resv held.
>- * read: vm->userptr.notifier_lock in write mode or vm->resv held.
>+ * write: vm->svm.gpusvm.notifier_lock in read mode and vm->resv held.
>+ * read: vm->svm.gpusvm.notifier_lock in write mode or vm->resv held.
> */
> bool initial_bind;
>- /** @mapped: Whether the @sgt sg-table is dma-mapped. Protected by @unmap_mutex. */
>- bool mapped;
> #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT)
> u32 divisor;
> #endif
>@@ -109,7 +104,7 @@ struct xe_vma {
> /**
> * @tile_present: GT mask of binding are present for this VMA.
> * protected by vm->lock, vm->resv and for userptrs,
>- * vm->userptr.notifier_lock for writing. Needs either for reading,
>+ * vm->svm.gpusvm.notifier_lock for writing. Needs either for reading,
> * but if reading is done under the vm->lock only, it needs to be held
> * in write mode.
> */
>@@ -243,11 +238,6 @@ struct xe_vm {
> * and needs repinning. Protected by @lock.
> */
> struct list_head repin_list;
>- /**
>- * @notifier_lock: protects notifier in write mode and
>- * submission in read mode.
>- */
>- struct rw_semaphore notifier_lock;
> /**
> * @userptr.invalidated_lock: Protects the
> * @userptr.invalidated list.
>--
>2.49.0
>
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2025-04-28 3:47 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-24 12:18 [PATCH v3 0/7] Replace xe_hmm with gpusvm Matthew Auld
2025-04-24 12:18 ` [PATCH v3 1/7] drm/gpusvm: fix hmm_pfn_to_map_order() usage Matthew Auld
2025-04-24 12:18 ` [PATCH v3 2/7] drm/gpusvm: use more selective dma dir in get_pages() Matthew Auld
2025-04-24 12:18 ` [PATCH v3 3/7] drm/gpusvm: pull out drm_gpusvm_pages substructure Matthew Auld
2025-04-24 12:18 ` [PATCH v3 4/7] drm/gpusvm: refactor core API to use pages struct Matthew Auld
2025-04-24 21:47 ` Matthew Brost
2025-04-24 12:18 ` [PATCH v3 5/7] drm/gpusvm: export drm_gpusvm_pages API Matthew Auld
2025-04-24 22:01 ` Matthew Brost
2025-04-24 22:04 ` Matthew Brost
2025-04-24 12:18 ` [PATCH v3 6/7] drm/xe/userptr: replace xe_hmm with gpusvm Matthew Auld
2025-04-24 14:21 ` kernel test robot
2025-04-24 14:42 ` kernel test robot
2025-04-24 23:17 ` Matthew Brost
2025-04-25 14:00 ` kernel test robot
2025-04-28 3:47 ` Dafna Hirschfeld
2025-04-24 12:18 ` [PATCH v3 7/7] drm/xe/pt: unify xe_pt_svm_pre_commit with userptr Matthew Auld
2025-04-24 15:43 ` kernel test robot
2025-04-24 23:18 ` Matthew Brost
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox