On Thu, Jun 18, 2026 at 04:08:58PM +0800, Honglei Huang wrote:
> From: Honglei Huang <[email protected]>
> 
> drm_gpusvm_pages_flags currently mixes two status:
>   - MM / virtual-address state: whether the range has been (partially)
>     unmapped by the Linux MM, these follow the lifetime of the VMA and
>     are a single per VA range fact.
>   - Device mapping state: has_devmem_pages and has_dma_mapping,
>     which describe the current page mapping status held by device
>     itself.
> 
> Keeping both on the pages object blurs the semantics of the
> abstraction of pages and VA range. So move the MM state flags onto the
> range, and keep drm_gpusvm_pages_flags strictly for mapping state.
> 
>   - Introduce drm_gpusvm_range_flags { migrate_devmem, unmapped,
>     partial_unmap } on drm_gpusvm_range.
>   - Shrink drm_gpusvm_pages_flags to just has_devmem_pages and
>     has_dma_mapping.
> 
> Side effect: drivers now need to check the unmap flags in the driver
> itself to avoid handling the unmapped pages.
> 
> Mirror that bit onto drm_gpusvm_pages so the framework can
> still short circuit drm_gpusvm_get_pages() under the notifier lock, and
> make drm_gpusvm_range_set_unmapped() propagate it to the backing pages.
> This follows Matt's review fixup for the v0 series; see the Link below.
> 
> Suggested-by: Matthew Brost <[email protected]>

Reviewed-by: Matthew Brost <[email protected]>

> Link: 
> https://gitlab.freedesktop.org/mbrost/xe-kernel-driver-svn-perf-6-15-2025/-/commit/623f6a50c037d9e44f6c9fbe6859a0ba7ad50177
> Signed-off-by: Honglei Huang <[email protected]>
> ---
>  drivers/gpu/drm/drm_gpusvm.c | 21 ++++++++++++++++++---
>  drivers/gpu/drm/xe/xe_svm.c  | 11 ++++++-----
>  include/drm/drm_gpusvm.h     | 30 +++++++++++++++++++++++++-----
>  3 files changed, 49 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
> index 958cb605aed..df900553f21 100644
> --- a/drivers/gpu/drm/drm_gpusvm.c
> +++ b/drivers/gpu/drm/drm_gpusvm.c
> @@ -641,7 +641,7 @@ drm_gpusvm_range_alloc(struct drm_gpusvm *gpusvm,
>       range->itree.last = ALIGN(fault_addr + 1, chunk_size) - 1;
>       INIT_LIST_HEAD(&range->entry);
>       range->pages.notifier_seq = LONG_MAX;
> -     range->pages.flags.migrate_devmem = migrate_devmem ? 1 : 0;
> +     range->flags.migrate_devmem = migrate_devmem ? 1 : 0;
>  
>       return range;
>  }
> @@ -1784,20 +1784,35 @@ EXPORT_SYMBOL_GPL(drm_gpusvm_has_mapping);
>  /**
>   * drm_gpusvm_range_set_unmapped() - Mark a GPU SVM range as unmapped
>   * @range: Pointer to the GPU SVM range structure.
> + * @pages: Pointer to the GPU SVM pages structure(s).
> + * @pages_count: Number of GPU SVM pages structure(s) passed in.
>   * @mmu_range: Pointer to the MMU notifier range structure.
>   *
>   * This function marks a GPU SVM range as unmapped and sets the 
> partial_unmap flag
>   * if the range partially falls within the provided MMU notifier range.
>   */
>  void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
> +                                struct drm_gpusvm_pages *pages,
> +                                unsigned int pages_count,
>                                  const struct mmu_notifier_range *mmu_range)
>  {
> +     unsigned int i;
> +
>       lockdep_assert_held_write(&range->gpusvm->notifier_lock);
>  
> -     range->pages.flags.unmapped = true;
> +     range->flags.unmapped = true;
> +     for (i = 0; i < pages_count; ++i) {
> +             struct drm_gpusvm_pages_flags flags = {
> +                     .__flags = pages[i].flags.__flags,
> +             };
> +
> +             flags.unmapped = true;
> +             /* WRITE_ONCE pairs with READ_ONCE for opportunistic checks */
> +             WRITE_ONCE(pages[i].flags.__flags, flags.__flags);
> +     }
>       if (drm_gpusvm_range_start(range) < mmu_range->start ||
>           drm_gpusvm_range_end(range) > mmu_range->end)
> -             range->pages.flags.partial_unmap = true;
> +             range->flags.partial_unmap = true;
>  }
>  EXPORT_SYMBOL_GPL(drm_gpusvm_range_set_unmapped);
>  
> diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
> index e1651e70c8f..63da149f3b7 100644
> --- a/drivers/gpu/drm/xe/xe_svm.c
> +++ b/drivers/gpu/drm/xe/xe_svm.c
> @@ -134,7 +134,8 @@ xe_svm_garbage_collector_add_range(struct xe_vm *vm, 
> struct xe_svm_range *range,
>  
>       range_debug(range, "GARBAGE COLLECTOR ADD");
>  
> -     drm_gpusvm_range_set_unmapped(&range->base, mmu_range);
> +     drm_gpusvm_range_set_unmapped(&range->base, &range->base.pages, 1,
> +                                   mmu_range);
>  
>       spin_lock(&vm->svm.garbage_collector.lock);
>       if (list_empty(&range->garbage_collector_link))
> @@ -166,7 +167,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.pages.flags.unmapped || !range->tile_present)
> +     if (range->base.flags.unmapped || !range->tile_present)
>               return 0;
>  
>       range_debug(range, "NOTIFIER - EXECUTE");
> @@ -1136,7 +1137,7 @@ bool xe_svm_range_needs_migrate_to_vram(struct 
> xe_svm_range *range, struct xe_vm
>       struct xe_vm *vm = range_to_vm(&range->base);
>       u64 range_size = xe_svm_range_size(range);
>  
> -     if (!range->base.pages.flags.migrate_devmem || !dpagemap)
> +     if (!range->base.flags.migrate_devmem || !dpagemap)
>               return false;
>  
>       xe_assert(vm->xe, IS_DGFX(vm->xe));
> @@ -1248,7 +1249,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, 
> struct xe_vma *vma,
>  
>       xe_svm_range_fault_count_stats_incr(gt, range);
>  
> -     if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) {
> +     if (ctx.devmem_only && !range->base.flags.migrate_devmem) {
>               err = -EACCES;
>               goto out;
>       }
> @@ -1623,7 +1624,7 @@ int xe_svm_alloc_vram(struct xe_svm_range *range, const 
> struct drm_gpusvm_ctx *c
>       int err, retries = 1;
>       bool write_locked = false;
>  
> -     xe_assert(range_to_vm(&range->base)->xe, 
> range->base.pages.flags.migrate_devmem);
> +     xe_assert(range_to_vm(&range->base)->xe, 
> range->base.flags.migrate_devmem);
>       range_debug(range, "ALLOCATE VRAM");
>  
>       migration_state = drm_gpusvm_scan_mm(&range->base,
> diff --git a/include/drm/drm_gpusvm.h b/include/drm/drm_gpusvm.h
> index 8a4d7134a9a..251a7266a73 100644
> --- a/include/drm/drm_gpusvm.h
> +++ b/include/drm/drm_gpusvm.h
> @@ -109,9 +109,7 @@ struct drm_gpusvm_notifier {
>  /**
>   * struct drm_gpusvm_pages_flags - Structure representing a GPU SVM pages 
> flags
>   *
> - * @migrate_devmem: Flag indicating whether the pages can be migrated to 
> device memory
>   * @unmapped: Flag indicating if the pages has been unmapped
> - * @partial_unmap: Flag indicating if the pages has been partially unmapped
>   * @has_devmem_pages: Flag indicating if the pages has devmem pages
>   * @has_dma_mapping: Flag indicating if the pages has a DMA mapping
>   * @__flags: Flags for pages in u16 form (used for READ_ONCE)
> @@ -119,11 +117,8 @@ struct drm_gpusvm_notifier {
>  struct drm_gpusvm_pages_flags {
>       union {
>               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;
>               };
> @@ -151,6 +146,27 @@ struct drm_gpusvm_pages {
>       struct drm_gpusvm_pages_flags flags;
>  };
>  
> +/**
> + * struct drm_gpusvm_range_flags - Range-level GPU SVM flags
> + *
> + * @migrate_devmem: Flag indicating whether the range can be migrated to 
> device memory
> + * @unmapped: Flag indicating if the range has been unmapped
> + * @partial_unmap: Flag indicating if the range has been partially unmapped
> + * @__flags: All flags in u16 form (used for READ_ONCE)
> + */
> +struct drm_gpusvm_range_flags {
> +     union {
> +             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 __flags;
> +     };
> +};
> +
>  /**
>   * struct drm_gpusvm_range - Structure representing a GPU SVM range
>   *
> @@ -160,6 +176,7 @@ struct drm_gpusvm_pages {
>   * @itree: Interval tree node for the range (inserted in GPU SVM notifier)
>   * @entry: List entry to fast interval tree traversal
>   * @pages: The pages for this range.
> + * @flags: Flags for range see &struct drm_gpusvm_range_flags
>   *
>   * This structure represents a GPU SVM range used for tracking memory ranges
>   * mapped in a DRM device.
> @@ -171,6 +188,7 @@ struct drm_gpusvm_range {
>       struct interval_tree_node itree;
>       struct list_head entry;
>       struct drm_gpusvm_pages pages;
> +     struct drm_gpusvm_range_flags flags;
>  };
>  
>  /**
> @@ -310,6 +328,8 @@ drm_gpusvm_range_find(struct drm_gpusvm_notifier 
> *notifier, unsigned long start,
>                     unsigned long end);
>  
>  void drm_gpusvm_range_set_unmapped(struct drm_gpusvm_range *range,
> +                                struct drm_gpusvm_pages *pages,
> +                                unsigned int pages_count,
>                                  const struct mmu_notifier_range *mmu_range);
>  
>  int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
> -- 
> 2.34.1
> 

Reply via email to