MADVISE_AUTORESET notifiers are only needed while the VMA is
CPU-only. After the first GPU fault, later unmaps follow the
normal SVM path.
Add an active flag so GPU-touched VMAs stop queueing autoreset
work. Broader notifiers from split VMAs may still remain active,
but the worker rechecks cpu_autoreset_active under vm->lock
before resetting attrs.
v2:
- Use plain bool active; callback reads it lockless. (Matt)
- Use wq check and mt_for_each in deactivate path. (Matt)
- Add lockdep_assert_held_write(&vm->lock) to xe_vm_madvise_gpu_touch().
v3:
- Deactivate only exact-match notifiers to preserve split siblings.
- Use READ_ONCE/WRITE_ONCE for notifier->active since the MMU notifier
callback reads it locklessly.
Cc: Matthew Brost <[email protected]>
Cc: Thomas Hellström <[email protected]>
Cc: Himal Prasad Ghimiray <[email protected]>
Signed-off-by: Arvind Yadav <[email protected]>
---
drivers/gpu/drm/xe/xe_pagefault.c | 5 +++-
drivers/gpu/drm/xe/xe_svm.c | 1 +
drivers/gpu/drm/xe/xe_vm_madvise.c | 47 +++++++++++++++++++++++++++++-
drivers/gpu/drm/xe/xe_vm_madvise.h | 1 +
drivers/gpu/drm/xe/xe_vm_types.h | 7 +++++
5 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/xe/xe_pagefault.c
b/drivers/gpu/drm/xe/xe_pagefault.c
index f64d3df08261..442a4fcad0c0 100644
--- a/drivers/gpu/drm/xe/xe_pagefault.c
+++ b/drivers/gpu/drm/xe/xe_pagefault.c
@@ -19,6 +19,7 @@
#include "xe_svm.h"
#include "xe_trace_bo.h"
#include "xe_vm.h"
+#include "xe_vm_madvise.h"
/**
* DOC: Xe page faults
@@ -222,8 +223,10 @@ static int xe_pagefault_service(struct xe_pagefault *pf)
/* First successful GPU fault ends CPU-only state. */
if (vma && xe_vma_is_cpu_addr_mirror(vma) &&
- xe_vma_has_cpu_autoreset_active(vma))
+ xe_vma_has_cpu_autoreset_active(vma)) {
xe_vma_gpu_touch(vma);
+ xe_vm_madvise_gpu_touch(vm, vma);
+ }
}
up_write(&vm->lock);
xe_vm_put(vm);
diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c
index e1651e70c8f0..b58857668d48 100644
--- a/drivers/gpu/drm/xe/xe_svm.c
+++ b/drivers/gpu/drm/xe/xe_svm.c
@@ -24,6 +24,7 @@
#include "xe_vm.h"
#include "xe_vm_types.h"
#include "xe_vram_types.h"
+#include "xe_vm_madvise.h"
/* Identifies subclasses of struct drm_pagemap_peer */
#define XE_PEER_PAGEMAP ((void *)0ul)
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c
b/drivers/gpu/drm/xe/xe_vm_madvise.c
index c2abe712598a..6c42ce8e3f52 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.c
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
@@ -948,7 +948,7 @@ static bool xe_madvise_notifier_callback(struct
mmu_interval_notifier *mni,
struct xe_vm *vm = notifier->vm;
u64 adj_start, adj_end;
- if (range->event != MMU_NOTIFY_UNMAP)
+ if (range->event != MMU_NOTIFY_UNMAP || !READ_ONCE(notifier->active))
return true;
if (!mmu_notifier_range_blockable(range))
@@ -1057,6 +1057,7 @@ xe_madvise_notifier_alloc(struct xe_vm *vm, u64 start,
u64 end)
notifier->vma_start = start;
notifier->vma_end = end;
INIT_LIST_HEAD(¬ifier->link);
+ WRITE_ONCE(notifier->active, true);
spin_lock_init(¬ifier->work_lock);
notifier->work_pending = false;
INIT_WORK(¬ifier->work, xe_madvise_work_func);
@@ -1186,6 +1187,7 @@ int xe_vm_madvise_register_notifier_range(struct xe_vm
*vm, u64 start, u64 end)
/* Dedup by stored range; tree slots can be fragmented by partial
overlap. */
list_for_each_entry(existing, &vm->svm.madvise_notifier_list, link) {
if (xe_madvise_notifier_exact(existing, start, end)) {
+ WRITE_ONCE(existing->active, true);
err = 0;
goto unlock_remove_new;
}
@@ -1236,3 +1238,46 @@ int xe_vm_madvise_register_notifier_range(struct xe_vm
*vm, u64 start, u64 end)
return err;
}
+
+/**
+ * xe_vm_deactivate_madvise_notifier_for_range - Disable callbacks for a VMA
+ * @vm: VM
+ * @start: VMA start
+ * @end: VMA end
+ */
+static void xe_vm_deactivate_madvise_notifier_for_range(struct xe_vm *vm, u64
start, u64 end)
+{
+ struct xe_madvise_notifier *notifier;
+ unsigned long index = start;
+
+ lockdep_assert_held_write(&vm->lock);
+
+ if (!vm->svm.madvise_work.wq)
+ return;
+
+ /*
+ * Only exact-match notifiers are disabled. Broader notifiers may still
+ * cover CPU-only split siblings.
+ */
+ mt_for_each(&vm->svm.madvise_notifiers, notifier, index, end - 1)
+ if (notifier->vma_start == start && notifier->vma_end == end)
+ WRITE_ONCE(notifier->active, false);
+}
+
+/**
+ * xe_vm_madvise_gpu_touch - Disable madvise notifier after GPU touch
+ * @vm: VM
+ * @vma: GPU-touched VMA
+ */
+void xe_vm_madvise_gpu_touch(struct xe_vm *vm, struct xe_vma *vma)
+{
+ lockdep_assert_held_write(&vm->lock);
+
+ /* Only AUTORESET VMAs have madvise notifiers. */
+ if (!(vma->gpuva.flags & XE_VMA_MADV_AUTORESET))
+ return;
+
+ xe_vm_deactivate_madvise_notifier_for_range(vm,
+ xe_vma_start(vma),
+ xe_vma_end(vma));
+}
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.h
b/drivers/gpu/drm/xe/xe_vm_madvise.h
index e2013605e190..d7ea6ff6b0c5 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.h
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.h
@@ -20,5 +20,6 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data,
int xe_vm_madvise_init(struct xe_vm *vm);
void xe_vm_madvise_fini(struct xe_vm *vm);
int xe_vm_madvise_register_notifier_range(struct xe_vm *vm, u64 start, u64
end);
+void xe_vm_madvise_gpu_touch(struct xe_vm *vm, struct xe_vma *vma);
#endif
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index d47bc338628d..4cb3fd619acf 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -50,6 +50,13 @@ struct xe_madvise_notifier {
u64 vma_end;
/** @link: Entry on vm->svm.madvise_notifier_list. */
struct list_head link;
+ /**
+ * @active: Fast-path callback gate.
+ *
+ * Read locklessly by the MMU notifier callback. The worker still checks
+ * cpu_autoreset_active under vm->lock before resetting attrs.
+ */
+ bool active;
/** @work_lock: Serialises pending interval state. */
spinlock_t work_lock;
/** @work_pending: Pending interval is available for the worker. */
--
2.43.0