* Re: [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier @ 2026-03-03 14:03 kernel test robot 0 siblings, 0 replies; 3+ messages in thread From: kernel test robot @ 2026-03-03 14:03 UTC (permalink / raw) To: oe-kbuild :::::: :::::: Manual check reason: "high confidence checkpatch report" :::::: BCC: lkp@intel.com CC: oe-kbuild-all@lists.linux.dev In-Reply-To: <20260303133409.11609-3-thomas.hellstrom@linux.intel.com> References: <20260303133409.11609-3-thomas.hellstrom@linux.intel.com> TO: "Thomas Hellström" <thomas.hellstrom@linux.intel.com> TO: intel-xe@lists.freedesktop.org Hi Thomas, kernel test robot noticed the following build warnings: [auto build test WARNING on drm-xe/drm-xe-next] [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/Thomas-Hellstr-m/mm-mmu_notifier-Allow-two-pass-struct-mmu_interval_notifiers/20260303-213841 base: https://gitlab.freedesktop.org/drm/xe/kernel.git drm-xe-next patch link: https://lore.kernel.org/r/20260303133409.11609-3-thomas.hellstrom%40linux.intel.com patch subject: [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier :::::: branch date: 23 minutes ago :::::: commit date: 23 minutes ago reproduce: (https://download.01.org/0day-ci/archive/20260303/202603031539.GzmPxSWq-lkp@intel.com/reproduce) # many are suggestions rather than must-fix ERROR:BAD_SIGN_OFF: Unrecognized email address: 'GitHub Copilot:claude-sonnet-4.6' #38: Assisted-by: GitHub Copilot:claude-sonnet-4.6 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v3 0/4] Two-pass MMU interval notifiers
@ 2026-03-03 13:34 Thomas Hellström
2026-03-03 13:34 ` [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier Thomas Hellström
0 siblings, 1 reply; 3+ messages in thread
From: Thomas Hellström @ 2026-03-03 13:34 UTC (permalink / raw)
To: intel-xe
Cc: Thomas Hellström, Matthew Brost, Jason Gunthorpe,
Andrew Morton, Simona Vetter, Dave Airlie, Alistair Popple,
dri-devel, linux-mm, linux-kernel, Christian König
GPU use-cases for mmu_interval_notifiers with hmm often involve
starting a gpu operation and then waiting for it to complete.
These operations are typically context preemption or TLB flushing.
With single-pass notifiers per GPU this doesn't scale in
multi-gpu scenarios. In those scenarios we'd want to first start
preemption- or TLB flushing on all GPUs and as a second pass wait
for them to complete.
This also applies in non-recoverable page-fault scenarios to
starting a preemption requests on GPUs and waiting for the GPUs
to preempt so that system pages they access can be reclaimed.
One can do this on per-driver basis multiplexing per-driver
notifiers but that would mean sharing the notifier "user" lock
across all GPUs and that doesn't scale well either, so adding support
for two-pass in the core appears like the right choice.
So this series does that, with pach 1 implementing the core support
and also describes the choices made.
The rest of the patches implements a POC with xeKMD userptr
invalidation and potential TLB-flushing. A follow-up series
will extend to drm_gpusvm.
v2 hightlights:
- Refactor the core mm patch to use the struct
mmu_interval_notifier_ops for the invalidate_finish() callback.
- Rebase on xe driver tlb invalidation changes.
- Provide an initial implementation for userptr instead of drm_gpusvm.
The intent is to handle drm_gpusvm in a follow-up series.
v3:
- Address review comments from Matt Brost: Code formatting,
documentation, additional asserts and removal of
unnecessary waits, as specified in each patch.
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Simona Vetter <simona.vetter@ffwll.ch>
Cc: Dave Airlie <airlied@gmail.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: <dri-devel@lists.freedesktop.org>
Cc: <linux-mm@kvack.org>
Cc: <linux-kernel@vger.kernel.org>
Thomas Hellström (4):
mm/mmu_notifier: Allow two-pass struct mmu_interval_notifiers
drm/xe/userptr: Convert invalidation to two-pass MMU notifier
drm/xe: Split TLB invalidation into submit and wait steps
drm/xe/userptr: Defer Waiting for TLB invalidation to the second pass
if possible
drivers/gpu/drm/xe/xe_svm.c | 8 +-
drivers/gpu/drm/xe/xe_tlb_inval.c | 84 +++++++++++++
drivers/gpu/drm/xe/xe_tlb_inval.h | 6 +
drivers/gpu/drm/xe/xe_tlb_inval_types.h | 14 +++
drivers/gpu/drm/xe/xe_userptr.c | 155 ++++++++++++++++++++----
drivers/gpu/drm/xe/xe_userptr.h | 31 ++++-
drivers/gpu/drm/xe/xe_vm.c | 99 +++++----------
drivers/gpu/drm/xe/xe_vm.h | 5 +-
drivers/gpu/drm/xe/xe_vm_madvise.c | 10 +-
drivers/gpu/drm/xe/xe_vm_types.h | 1 +
include/linux/mmu_notifier.h | 38 ++++++
mm/mmu_notifier.c | 65 ++++++++--
12 files changed, 412 insertions(+), 104 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier 2026-03-03 13:34 [PATCH v3 0/4] Two-pass MMU interval notifiers Thomas Hellström @ 2026-03-03 13:34 ` Thomas Hellström 2026-03-03 18:10 ` Matthew Brost 0 siblings, 1 reply; 3+ messages in thread From: Thomas Hellström @ 2026-03-03 13:34 UTC (permalink / raw) To: intel-xe Cc: Thomas Hellström, Matthew Brost, Christian König, dri-devel, Jason Gunthorpe, Andrew Morton, Simona Vetter, Dave Airlie, Alistair Popple, linux-mm, linux-kernel In multi-GPU scenarios, asynchronous GPU job latency is a bottleneck if each notifier waits for its own GPU before returning. The two-pass mmu_interval_notifier infrastructure allows deferring the wait to a second pass, so all GPUs can be signalled in the first pass before any of them are waited on. Convert the userptr invalidation to use the two-pass model: Use invalidate_start as the first pass to mark the VMA for repin and enable software signalling on the VM reservation fences to start any gpu work needed for signaling. Fall back to completing the work synchronously if all fences are already signalled, or if a concurrent invalidation is already using the embedded finish structure. Use invalidate_finish as the second pass to wait for the reservation fences to complete, invalidate the GPU TLB in fault mode, and unmap the gpusvm pages. Embed a struct mmu_interval_notifier_finish in struct xe_userptr to avoid dynamic allocation in the notifier callback. Use a finish_inuse flag to prevent two concurrent invalidations from using it simultaneously; fall back to the synchronous path for the second caller. v3: - Add locking asserts in notifier components (Matt Brost) - Clean up newlines (Matt Brost) - Update the userptr notifier state member locking documentation (Matt Brost) Assisted-by: GitHub Copilot:claude-sonnet-4.6 Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com> --- drivers/gpu/drm/xe/xe_userptr.c | 108 +++++++++++++++++++++++++------- drivers/gpu/drm/xe/xe_userptr.h | 14 ++++- 2 files changed, 99 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index e120323c43bc..37032b8125a6 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -10,6 +10,14 @@ #include "xe_trace_bo.h" +static void xe_userptr_assert_in_notifier(struct xe_vm *vm) +{ + lockdep_assert(lockdep_is_held_type(&vm->svm.gpusvm.notifier_lock, 0) || + (lockdep_is_held(&vm->lock) && + lockdep_is_held_type(&vm->svm.gpusvm.notifier_lock, 1) && + dma_resv_held(xe_vm_resv(vm)))); +} + /** * xe_vma_userptr_check_repin() - Advisory check for repin needed * @uvma: The userptr vma @@ -73,18 +81,46 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma) &ctx); } -static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uvma) +static void xe_vma_userptr_do_inval(struct xe_vm *vm, struct xe_userptr_vma *uvma, + bool is_deferred) { struct xe_userptr *userptr = &uvma->userptr; struct xe_vma *vma = &uvma->vma; - struct dma_resv_iter cursor; - struct dma_fence *fence; struct drm_gpusvm_ctx ctx = { .in_notifier = true, .read_only = xe_vma_read_only(vma), }; long err; + xe_userptr_assert_in_notifier(vm); + + err = dma_resv_wait_timeout(xe_vm_resv(vm), + DMA_RESV_USAGE_BOOKKEEP, + false, MAX_SCHEDULE_TIMEOUT); + XE_WARN_ON(err <= 0); + + if (xe_vm_in_fault_mode(vm) && userptr->initial_bind) { + err = xe_vm_invalidate_vma(vma); + XE_WARN_ON(err); + } + + if (is_deferred) + userptr->finish_inuse = false; + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages, + xe_vma_size(vma) >> PAGE_SHIFT, &ctx); +} + +static struct mmu_interval_notifier_finish * +xe_vma_userptr_invalidate_pass1(struct xe_vm *vm, struct xe_userptr_vma *uvma) +{ + struct xe_userptr *userptr = &uvma->userptr; + struct xe_vma *vma = &uvma->vma; + struct dma_resv_iter cursor; + struct dma_fence *fence; + bool signaled = true; + + xe_userptr_assert_in_notifier(vm); + /* * Tell exec and rebind worker they need to repin and rebind this * userptr. @@ -105,27 +141,32 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv */ dma_resv_iter_begin(&cursor, xe_vm_resv(vm), DMA_RESV_USAGE_BOOKKEEP); - dma_resv_for_each_fence_unlocked(&cursor, fence) + dma_resv_for_each_fence_unlocked(&cursor, fence) { dma_fence_enable_sw_signaling(fence); + if (signaled && !dma_fence_is_signaled(fence)) + signaled = false; + } dma_resv_iter_end(&cursor); - err = dma_resv_wait_timeout(xe_vm_resv(vm), - DMA_RESV_USAGE_BOOKKEEP, - false, MAX_SCHEDULE_TIMEOUT); - XE_WARN_ON(err <= 0); - - if (xe_vm_in_fault_mode(vm) && userptr->initial_bind) { - err = xe_vm_invalidate_vma(vma); - XE_WARN_ON(err); + /* + * Only one caller at a time can use the multi-pass state. + * If it's already in use, or all fences are already signaled, + * proceed directly to invalidation without deferring. + */ + if (signaled || userptr->finish_inuse) { + xe_vma_userptr_do_inval(vm, uvma, false); + return NULL; } - drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages, - xe_vma_size(vma) >> PAGE_SHIFT, &ctx); + userptr->finish_inuse = true; + + return &userptr->finish; } -static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni, - const struct mmu_notifier_range *range, - unsigned long cur_seq) +static bool xe_vma_userptr_invalidate_start(struct mmu_interval_notifier *mni, + const struct mmu_notifier_range *range, + unsigned long cur_seq, + struct mmu_interval_notifier_finish **p_finish) { struct xe_userptr_vma *uvma = container_of(mni, typeof(*uvma), userptr.notifier); struct xe_vma *vma = &uvma->vma; @@ -138,21 +179,40 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni, return false; vm_dbg(&xe_vma_vm(vma)->xe->drm, - "NOTIFIER: addr=0x%016llx, range=0x%016llx", + "NOTIFIER PASS1: addr=0x%016llx, range=0x%016llx", xe_vma_start(vma), xe_vma_size(vma)); down_write(&vm->svm.gpusvm.notifier_lock); mmu_interval_set_seq(mni, cur_seq); - __vma_userptr_invalidate(vm, uvma); + *p_finish = xe_vma_userptr_invalidate_pass1(vm, uvma); + up_write(&vm->svm.gpusvm.notifier_lock); - trace_xe_vma_userptr_invalidate_complete(vma); + if (!*p_finish) + trace_xe_vma_userptr_invalidate_complete(vma); return true; } +static void xe_vma_userptr_invalidate_finish(struct mmu_interval_notifier_finish *finish) +{ + struct xe_userptr_vma *uvma = container_of(finish, typeof(*uvma), userptr.finish); + struct xe_vma *vma = &uvma->vma; + struct xe_vm *vm = xe_vma_vm(vma); + + vm_dbg(&xe_vma_vm(vma)->xe->drm, + "NOTIFIER PASS2: addr=0x%016llx, range=0x%016llx", + xe_vma_start(vma), xe_vma_size(vma)); + + down_write(&vm->svm.gpusvm.notifier_lock); + xe_vma_userptr_do_inval(vm, uvma, true); + up_write(&vm->svm.gpusvm.notifier_lock); + trace_xe_vma_userptr_invalidate_complete(vma); +} + static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { - .invalidate = vma_userptr_invalidate, + .invalidate_start = xe_vma_userptr_invalidate_start, + .invalidate_finish = xe_vma_userptr_invalidate_finish, }; #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) @@ -164,6 +224,7 @@ static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { */ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) { + static struct mmu_interval_notifier_finish *finish; struct xe_vm *vm = xe_vma_vm(&uvma->vma); /* Protect against concurrent userptr pinning */ @@ -179,7 +240,10 @@ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) if (!mmu_interval_read_retry(&uvma->userptr.notifier, uvma->userptr.pages.notifier_seq)) uvma->userptr.pages.notifier_seq -= 2; - __vma_userptr_invalidate(vm, uvma); + + finish = xe_vma_userptr_invalidate_pass1(vm, uvma); + if (finish) + xe_vma_userptr_do_inval(vm, uvma, true); } #endif diff --git a/drivers/gpu/drm/xe/xe_userptr.h b/drivers/gpu/drm/xe/xe_userptr.h index ef801234991e..e1830c2f5fd2 100644 --- a/drivers/gpu/drm/xe/xe_userptr.h +++ b/drivers/gpu/drm/xe/xe_userptr.h @@ -56,7 +56,19 @@ struct xe_userptr { * @notifier: MMU notifier for user pointer (invalidation call back) */ struct mmu_interval_notifier notifier; - + /** + * @finish: MMU notifier finish structure for two-pass invalidation. + * Embedded here to avoid allocation in the notifier callback. + * Protected by struct xe_vm::svm.gpusvm.notifier_lock in write mode + * alternatively by the same lock in read mode *and* the vm resv held. + */ + struct mmu_interval_notifier_finish finish; + /** + * @finish_inuse: Whether @finish is currently in use by an in-progress + * two-pass invalidation. + * Protected using the same locking as @finish. + */ + bool finish_inuse; /** * @initial_bind: user pointer has been bound at least once. * write: vm->svm.gpusvm.notifier_lock in read mode and vm->resv held. -- 2.53.0 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier 2026-03-03 13:34 ` [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier Thomas Hellström @ 2026-03-03 18:10 ` Matthew Brost 0 siblings, 0 replies; 3+ messages in thread From: Matthew Brost @ 2026-03-03 18:10 UTC (permalink / raw) To: Thomas Hellström Cc: intel-xe, Christian König, dri-devel, Jason Gunthorpe, Andrew Morton, Simona Vetter, Dave Airlie, Alistair Popple, linux-mm, linux-kernel On Tue, Mar 03, 2026 at 02:34:07PM +0100, Thomas Hellström wrote: > In multi-GPU scenarios, asynchronous GPU job latency is a bottleneck if > each notifier waits for its own GPU before returning. The two-pass > mmu_interval_notifier infrastructure allows deferring the wait to a > second pass, so all GPUs can be signalled in the first pass before > any of them are waited on. > > Convert the userptr invalidation to use the two-pass model: > > Use invalidate_start as the first pass to mark the VMA for repin and > enable software signalling on the VM reservation fences to start any > gpu work needed for signaling. Fall back to completing the work > synchronously if all fences are already signalled, or if a concurrent > invalidation is already using the embedded finish structure. > > Use invalidate_finish as the second pass to wait for the reservation > fences to complete, invalidate the GPU TLB in fault mode, and unmap > the gpusvm pages. > > Embed a struct mmu_interval_notifier_finish in struct xe_userptr to > avoid dynamic allocation in the notifier callback. Use a finish_inuse > flag to prevent two concurrent invalidations from using it > simultaneously; fall back to the synchronous path for the second caller. > > v3: > - Add locking asserts in notifier components (Matt Brost) > - Clean up newlines (Matt Brost) > - Update the userptr notifier state member locking documentation > (Matt Brost) > > Assisted-by: GitHub Copilot:claude-sonnet-4.6 > Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com> Reviewed-by: Matthew Brost <matthew.brost@intel.com> > --- > drivers/gpu/drm/xe/xe_userptr.c | 108 +++++++++++++++++++++++++------- > drivers/gpu/drm/xe/xe_userptr.h | 14 ++++- > 2 files changed, 99 insertions(+), 23 deletions(-) > > diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c > index e120323c43bc..37032b8125a6 100644 > --- a/drivers/gpu/drm/xe/xe_userptr.c > +++ b/drivers/gpu/drm/xe/xe_userptr.c > @@ -10,6 +10,14 @@ > > #include "xe_trace_bo.h" > > +static void xe_userptr_assert_in_notifier(struct xe_vm *vm) > +{ > + lockdep_assert(lockdep_is_held_type(&vm->svm.gpusvm.notifier_lock, 0) || > + (lockdep_is_held(&vm->lock) && > + lockdep_is_held_type(&vm->svm.gpusvm.notifier_lock, 1) && > + dma_resv_held(xe_vm_resv(vm)))); > +} > + > /** > * xe_vma_userptr_check_repin() - Advisory check for repin needed > * @uvma: The userptr vma > @@ -73,18 +81,46 @@ int xe_vma_userptr_pin_pages(struct xe_userptr_vma *uvma) > &ctx); > } > > -static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uvma) > +static void xe_vma_userptr_do_inval(struct xe_vm *vm, struct xe_userptr_vma *uvma, > + bool is_deferred) > { > struct xe_userptr *userptr = &uvma->userptr; > struct xe_vma *vma = &uvma->vma; > - struct dma_resv_iter cursor; > - struct dma_fence *fence; > struct drm_gpusvm_ctx ctx = { > .in_notifier = true, > .read_only = xe_vma_read_only(vma), > }; > long err; > > + xe_userptr_assert_in_notifier(vm); > + > + err = dma_resv_wait_timeout(xe_vm_resv(vm), > + DMA_RESV_USAGE_BOOKKEEP, > + false, MAX_SCHEDULE_TIMEOUT); > + XE_WARN_ON(err <= 0); > + > + if (xe_vm_in_fault_mode(vm) && userptr->initial_bind) { > + err = xe_vm_invalidate_vma(vma); > + XE_WARN_ON(err); > + } > + > + if (is_deferred) > + userptr->finish_inuse = false; > + drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages, > + xe_vma_size(vma) >> PAGE_SHIFT, &ctx); > +} > + > +static struct mmu_interval_notifier_finish * > +xe_vma_userptr_invalidate_pass1(struct xe_vm *vm, struct xe_userptr_vma *uvma) > +{ > + struct xe_userptr *userptr = &uvma->userptr; > + struct xe_vma *vma = &uvma->vma; > + struct dma_resv_iter cursor; > + struct dma_fence *fence; > + bool signaled = true; > + > + xe_userptr_assert_in_notifier(vm); > + > /* > * Tell exec and rebind worker they need to repin and rebind this > * userptr. > @@ -105,27 +141,32 @@ static void __vma_userptr_invalidate(struct xe_vm *vm, struct xe_userptr_vma *uv > */ > dma_resv_iter_begin(&cursor, xe_vm_resv(vm), > DMA_RESV_USAGE_BOOKKEEP); > - dma_resv_for_each_fence_unlocked(&cursor, fence) > + dma_resv_for_each_fence_unlocked(&cursor, fence) { > dma_fence_enable_sw_signaling(fence); > + if (signaled && !dma_fence_is_signaled(fence)) > + signaled = false; > + } > dma_resv_iter_end(&cursor); > > - err = dma_resv_wait_timeout(xe_vm_resv(vm), > - DMA_RESV_USAGE_BOOKKEEP, > - false, MAX_SCHEDULE_TIMEOUT); > - XE_WARN_ON(err <= 0); > - > - if (xe_vm_in_fault_mode(vm) && userptr->initial_bind) { > - err = xe_vm_invalidate_vma(vma); > - XE_WARN_ON(err); > + /* > + * Only one caller at a time can use the multi-pass state. > + * If it's already in use, or all fences are already signaled, > + * proceed directly to invalidation without deferring. > + */ > + if (signaled || userptr->finish_inuse) { > + xe_vma_userptr_do_inval(vm, uvma, false); > + return NULL; > } > > - drm_gpusvm_unmap_pages(&vm->svm.gpusvm, &uvma->userptr.pages, > - xe_vma_size(vma) >> PAGE_SHIFT, &ctx); > + userptr->finish_inuse = true; > + > + return &userptr->finish; > } > > -static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni, > - const struct mmu_notifier_range *range, > - unsigned long cur_seq) > +static bool xe_vma_userptr_invalidate_start(struct mmu_interval_notifier *mni, > + const struct mmu_notifier_range *range, > + unsigned long cur_seq, > + struct mmu_interval_notifier_finish **p_finish) > { > struct xe_userptr_vma *uvma = container_of(mni, typeof(*uvma), userptr.notifier); > struct xe_vma *vma = &uvma->vma; > @@ -138,21 +179,40 @@ static bool vma_userptr_invalidate(struct mmu_interval_notifier *mni, > return false; > > vm_dbg(&xe_vma_vm(vma)->xe->drm, > - "NOTIFIER: addr=0x%016llx, range=0x%016llx", > + "NOTIFIER PASS1: addr=0x%016llx, range=0x%016llx", > xe_vma_start(vma), xe_vma_size(vma)); > > down_write(&vm->svm.gpusvm.notifier_lock); > mmu_interval_set_seq(mni, cur_seq); > > - __vma_userptr_invalidate(vm, uvma); > + *p_finish = xe_vma_userptr_invalidate_pass1(vm, uvma); > + > up_write(&vm->svm.gpusvm.notifier_lock); > - trace_xe_vma_userptr_invalidate_complete(vma); > + if (!*p_finish) > + trace_xe_vma_userptr_invalidate_complete(vma); > > return true; > } > > +static void xe_vma_userptr_invalidate_finish(struct mmu_interval_notifier_finish *finish) > +{ > + struct xe_userptr_vma *uvma = container_of(finish, typeof(*uvma), userptr.finish); > + struct xe_vma *vma = &uvma->vma; > + struct xe_vm *vm = xe_vma_vm(vma); > + > + vm_dbg(&xe_vma_vm(vma)->xe->drm, > + "NOTIFIER PASS2: addr=0x%016llx, range=0x%016llx", > + xe_vma_start(vma), xe_vma_size(vma)); > + > + down_write(&vm->svm.gpusvm.notifier_lock); > + xe_vma_userptr_do_inval(vm, uvma, true); > + up_write(&vm->svm.gpusvm.notifier_lock); > + trace_xe_vma_userptr_invalidate_complete(vma); > +} > + > static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { > - .invalidate = vma_userptr_invalidate, > + .invalidate_start = xe_vma_userptr_invalidate_start, > + .invalidate_finish = xe_vma_userptr_invalidate_finish, > }; > > #if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) > @@ -164,6 +224,7 @@ static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { > */ > void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) > { > + static struct mmu_interval_notifier_finish *finish; > struct xe_vm *vm = xe_vma_vm(&uvma->vma); > > /* Protect against concurrent userptr pinning */ > @@ -179,7 +240,10 @@ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) > if (!mmu_interval_read_retry(&uvma->userptr.notifier, > uvma->userptr.pages.notifier_seq)) > uvma->userptr.pages.notifier_seq -= 2; > - __vma_userptr_invalidate(vm, uvma); > + > + finish = xe_vma_userptr_invalidate_pass1(vm, uvma); > + if (finish) > + xe_vma_userptr_do_inval(vm, uvma, true); > } > #endif > > diff --git a/drivers/gpu/drm/xe/xe_userptr.h b/drivers/gpu/drm/xe/xe_userptr.h > index ef801234991e..e1830c2f5fd2 100644 > --- a/drivers/gpu/drm/xe/xe_userptr.h > +++ b/drivers/gpu/drm/xe/xe_userptr.h > @@ -56,7 +56,19 @@ struct xe_userptr { > * @notifier: MMU notifier for user pointer (invalidation call back) > */ > struct mmu_interval_notifier notifier; > - > + /** > + * @finish: MMU notifier finish structure for two-pass invalidation. > + * Embedded here to avoid allocation in the notifier callback. > + * Protected by struct xe_vm::svm.gpusvm.notifier_lock in write mode > + * alternatively by the same lock in read mode *and* the vm resv held. > + */ > + struct mmu_interval_notifier_finish finish; > + /** > + * @finish_inuse: Whether @finish is currently in use by an in-progress > + * two-pass invalidation. > + * Protected using the same locking as @finish. > + */ > + bool finish_inuse; > /** > * @initial_bind: user pointer has been bound at least once. > * write: vm->svm.gpusvm.notifier_lock in read mode and vm->resv held. > -- > 2.53.0 > ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-03 18:10 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-03 14:03 [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier kernel test robot -- strict thread matches above, loose matches on Subject: below -- 2026-03-03 13:34 [PATCH v3 0/4] Two-pass MMU interval notifiers Thomas Hellström 2026-03-03 13:34 ` [PATCH v3 2/4] drm/xe/userptr: Convert invalidation to two-pass MMU notifier Thomas Hellström 2026-03-03 18:10 ` Matthew Brost
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.