From: "Yadav, Arvind" <arvind.yadav@intel.com>
To: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
"Matthew Brost" <matthew.brost@intel.com>
Cc: <intel-xe@lists.freedesktop.org>,
<himal.prasad.ghimiray@intel.com>, <pallavi.mishra@intel.com>
Subject: Re: [PATCH v5 6/9] drm/xe/madvise: Implement per-VMA purgeable state tracking
Date: Wed, 25 Feb 2026 15:10:46 +0530 [thread overview]
Message-ID: <02b79322-f378-4e4f-befc-3f9bba9f7830@intel.com> (raw)
In-Reply-To: <1fd477061dedf58f0e23d6b8e6715fdab50f88ef.camel@linux.intel.com>
On 25-02-2026 14:48, Thomas Hellström wrote:
> On Wed, 2026-02-25 at 01:04 -0800, Matthew Brost wrote:
>> On Wed, Feb 25, 2026 at 09:21:10AM +0100, Thomas Hellström wrote:
>>> On Wed, 2026-02-25 at 11:05 +0530, Yadav, Arvind wrote:
>>>> On 24-02-2026 22:06, Matthew Brost wrote:
>>>>> On Tue, Feb 24, 2026 at 08:37:44PM +0530, Yadav, Arvind wrote:
>>>>>> On 24-02-2026 18:18, Thomas Hellström wrote:
>>>>>>> On Wed, 2026-02-11 at 20:56 +0530, Arvind Yadav wrote:
>>>>>>>> Track purgeable state per-VMA instead of using a coarse
>>>>>>>> shared
>>>>>>>> BO check. This prevents purging shared BOs until all VMAs
>>>>>>>> across
>>>>>>>> all VMs are marked DONTNEED.
>>>>>>>>
>>>>>>>> Add xe_bo_all_vmas_dontneed() to check all VMAs before
>>>>>>>> marking
>>>>>>>> a BO purgeable. Add
>>>>>>>> xe_bo_recheck_purgeable_on_vma_unbind()
>>>>>>>> to
>>>>>>>> handle state transitions when VMAs are destroyed - if all
>>>>>>>> remaining VMAs are DONTNEED the BO can become purgeable,
>>>>>>>> or
>>>>>>>> if
>>>>>>>> no VMAs remain it transitions to WILLNEED.
>>>>>>>>
>>>>>>>> The per-VMA purgeable_state field stores the madvise hint
>>>>>>>> for
>>>>>>>> each mapping. Shared BOs can only be purged when all VMAs
>>>>>>>> unanimously indicate DONTNEED.
>>>>>>>>
>>>>>>>> One thing to note: when the last VMA goes away, we
>>>>>>>> default
>>>>>>>> back to
>>>>>>>> WILLNEED. DONTNEED is a per-mapping hint, and without any
>>>>>>>> mappings
>>>>>>>> there is no remaining madvise state to justify purging.
>>>>>>>> This
>>>>>>>> prevents
>>>>>>>> BOs from becoming purgeable solely due to being
>>>>>>>> temporarily
>>>>>>>> unmapped.
>>>>>>>>
>>>>>>>> v3:
>>>>>>>> - This addresses Thomas Hellström's feedback: "loop
>>>>>>>> over
>>>>>>>> all vmas
>>>>>>>> attached to the bo and check that they all say
>>>>>>>> WONTNEED. This
>>>>>>>> will
>>>>>>>> also need a check at VMA unbinding"
>>>>>>>>
>>>>>>>> v4:
>>>>>>>> - @madv_purgeable atomic_t → u32 change across all
>>>>>>>> relevant
>>>>>>>> patches (Matt)
>>>>>>>>
>>>>>>>> v5:
>>>>>>>> - Call xe_bo_recheck_purgeable_on_vma_unbind() from
>>>>>>>> xe_vma_destroy()
>>>>>>>> right after drm_gpuva_unlink() where we already
>>>>>>>> hold
>>>>>>>> the BO lock,
>>>>>>>> drop the trylock-based late destroy path (Matt)
>>>>>>>> - Move purgeable_state into xe_vma_mem_attr with the
>>>>>>>> other madvise
>>>>>>>> attributes (Matt)
>>>>>>>> - Drop READ_ONCE since the BO lock already protects
>>>>>>>> us
>>>>>>>> (Matt)
>>>>>>>> - Keep returning false when there are no VMAs -
>>>>>>>> otherwise
>>>>>>>> we'd mark
>>>>>>>> BOs purgeable without any user hint (Matt)
>>>>>>>> - Use xe_bo_set_purgeable_state() instead of direct
>>>>>>>> initialization(Matt)
>>>>>>>> - use xe_assert instead of drm_war (Thomas)
>>>>>>> Typo.
>>>>>> Noted,
>>>>>>
>>>>>>> There were also a couple of review issues in my reply here:
>>>>>>>
>>>>>>> https://patchwork.freedesktop.org/patch/699451/?series=156651&rev=5
>>>>>>>
>>>>>>> that were never addressed or at least commented upon.
>>>>>>>
>>>>>>> The comment there on retaining purgeable state after the
>>>>>>> last
>>>>>>> vma is
>>>>>>> unmapped could be discussed, though.
>>>>>>>
>>>>>>> Let's say we unmap a vma marking a bo purgeable. It then
>>>>>>> becomes either
>>>>>>> purged or non-purgeable.
>>>>>>>
>>>>>>> Then an app tries to access it either using a new vma or
>>>>>>> CPU
>>>>>>> map. Then
>>>>>>> it will typically succeed, or might occasionally fail if
>>>>>>> the bo
>>>>>>> happened to be purged in between.
>>>>>>>
>>>>>>> How do we handle new vma map requests and cpu-faults to a
>>>>>>> bo in
>>>>>>> purgeable state? Do we block those?
>>>>>> @Thomas,
>>>>>>
>>>>>> The implementation already blocks new access to purged BOs:
>>>>>> 1. New VMA mappings (Patch 0005): vma_lock_and_validate()
>>>>>> rejects MAP
>>>>>> operations to purged BOs with -EINVAL via the check_purged
>>>>>> flag.
>>>>>> 2. CPU faults (Patch 0004): Both xe_bo_cpu_prep() and
>>>>>> xe_gem_mmap_offset()
>>>>>> return errors (-EFAULT / VM_FAULT_SIGBUS) when accessing
>>>>>> purged
>>>>>> BOs.
>>>>>> 3 . "Once purged, always purged": Even when the last VMA is
>>>>>> unmapped,
>>>>>> xe_bo_recompute_purgeable_state() preserves the PURGED state
>>>>>> - it
>>>>>> never
>>>>>> transitions back to WILLNEED or DONTNEED (see early return at
>>>>>> the
>>>>>> top of the
>>>>>> function).
>>>>>>
>>>>>> The only way forward for the application is to destroy the
>>>>>> purged
>>>>>> BO and
>>>>>> create a new one.
>>>>>>
>>>>>> Regarding the 'no VMAs → WILLNEED' logic: this only applies
>>>>>> to
>>>>>> non-purged
>>>>>> BOs that happen to be temporarily unmapped. Purged BOs remain
>>>>>> permanently
>>>>>> invalid.
>>>>> So I think xe_bo_all_vmas_dontneed() isn't 100% correct...
>>>>>
>>>>> I think should return an enum...
>>>>>
>>>>> enum xe_bo_vmas_purge_state { /* Maybe a better name? */
>>>>> XE_BO_VMAS_STATE_DONTNEED = 0,
>>>>> XE_BO_VMAS_STATE_WILLNEED = 1,
>>>>> XE_BO_VMAS_STATE_NO_VMAS = 2,
>>>>> };
>>>>>
>>>>>
>>>>> Then in xe_bo_recompute_purgeable_state() something like this:
>>>>>
>>>>> void xe_bo_recompute_purgeable_state(struct xe_bo *bo)
>>>>> {
>>>>> enum xe_bo_vma_purge_state state;
>>>>>
>>>>> if (!bo)
>>>>> return;
>>>>>
>>>>> xe_bo_assert_held(bo);
>>>>>
>>>>> /*
>>>>> * Once purged, always purged. Cannot transition back
>>>>> to
>>>>> WILLNEED.
>>>>> * This matches i915 semantics where purged BOs are
>>>>> permanently invalid.
>>>>> */
>>>>> if (bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED)
>>>>> return;
>>>>>
>>>>> state = xe_bo_all_vmas_dontneed(bo);
>>>>> if (state == XE_BO_VMAS_STATE_DONTNEED) {
>>>>> /* All VMAs are DONTNEED - mark BO purgeable
>>>>> */
>>>>> if (bo->madv_purgeable !=
>>>>> XE_MADV_PURGEABLE_DONTNEED)
>>>>> xe_bo_set_purgeable_state(bo,
>>>>> XE_MADV_PURGEABLE_DONTNEED);
>>>>> } else if (state == XE_BO_VMAS_STATE_WILLNEED) {
>>>>> /* At least one VMA is WILLNEED - BO must not
>>>>> be
>>>>> purgeable */
>>>>> if (bo->madv_purgeable !=
>>>>> XE_MADV_PURGEABLE_WILLNEED)
>>>>> xe_bo_set_purgeable_state(bo,
>>>>> XE_MADV_PURGEABLE_WILLNEED);
>>>>> }
>>>>> }
>>>>>
>>>>> I think would avoid the last unbind unintentionally flipping
>>>>> from
>>>>> DONTNEED -> WILLNEED.
>>>>>
>>>>> What do you both of you (Thomas, Arvind) think?
>>>>
>>>> @Matt,
>>>>
>>>> Good catch—I missed that transition. You’re right: when the last
>>>> VMA
>>>> is
>>>> unmapped from a DONTNEED BO, the current logic can flip it back
>>>> to
>>>> WILLNEED, which discards the user’s hint. That’s wrong.
>>>>
>>>> I like the enum approach to distinguish:
>>>> - *_DONTNEED: all VMAs are DONTNEED
>>>> - *_WILLNEED: at least one VMA is WILLNEED
>>>> - *_NO_VMAS: no VMAs present
>>>>
>>>> With that, xe_bo_recompute_purgeable_state() can avoid changing
>>>> state
>>>> on
>>>> NO_VMAS and preserve "once purged, always purged," matching i915
>>>> semantics. This also addresses Thomas's earlier question about
>>>> new
>>>> VMA/CPU access to purgeable BOs—the enum makes it clear we only
>>>> transition on explicit VMA state, not on absence of VMAs.
>>>>
>>>> I'll rework xe_bo_all_vmas_dontneed() to return the enum and
>>>> update
>>>> the
>>>> recompute path accordingly.
>>>>
>>>>
>>>> @Thomas,
>>>>
>>>> Does this direction look good to you? If yes, I will send updated
>>>> patch.
>>> Yes, but I'm also as mentioned concerned about whether we can add
>>> new
>>> vmas, cpu faults and exports in the WONTNEED state. If we can do
>>> that,
>>> it might succeed most of the time making a well-behave appearance
>>> in
>>> user-space, but if on occation the bo gets purged, the app would
>>> seeming unexpectedly fail.
>>>
>>> So do we block new vmas cpu-faults and exports in the WONTNEED
>>> state?
>>>
>> I’ve thought about the same thing. The new vmas semantics are a bit
>> odd,
>> because if you unbind the BO in WONTNEED and disallow creating new
>> VMAs,
>> the BO can never be used again—madvise requires a VMA to operate thus
>> you can't move a BO out of WONTNEED. Maybe that’s acceptable or even
>> desirable, but it would need to be documented, and ultimately we’d
>> need
>> a UMD ack for those semantics.
>>
>> CPU faults or exports in WONTNEED also seem like they should be
>> disallowed with less odd sematics, but again, this should be
>> documented
>> and require UMD ack.
> Hmm. With WONTNEED really to do as little as possible. So we shouldn't
> go to into any sort of unmapping GPU- or CPU ptes. That means the end
> behaviour might still be a bit erratic on access of a WONTNEED bo,
> depending on previous access pattern we may or may not fault.
>
> So we should probably disallow mmap(), VM_BIND and export, but allow
> CPU- and GPU pagefaults. And document.
>
> Speaking of pagefaults, I noticed that when *purged*, it looks like we
> populate with scratch PTEs also on faulting VMs. I think this is the
> correct approach, though, to avoid the prefetch pagefaults wreaking
> havoc if accessing vmas with purged bos.
@Thomas, @Matt,
Got it. So the plan is:
DONTNEED BOs:
- Block: new mmap(), VM_BIND, dma-buf export
- Allow: CPU/GPU faults on existing mappings (fail if purged)
- Keep PTEs intact, just mark as purgeable
I'll add checks in:
1. xe_gem_mmap_offset() - reject new mmap to DONTNEED BO
2. VM_BIND path (vma_lock_and_validate) - reject new VMA to DONTNEED BO
3. dma-buf export path - reject export of DONTNEED BO
Let me know if I am missing something.
Thanks,
Arvind
> /Thomas
>
>
>> Matt
>>
>>> /Thomas
>>>
>>>
>>>> Thanks,
>>>> Arvind
>>>>
>>>>
>>>>> Matt
>>>>>
>>>>>> Thanks,
>>>>>> Arvind
>>>>>>> Thanks,
>>>>>>> Thomas
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> Cc: Matthew Brost <matthew.brost@intel.com>
>>>>>>>> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>>>>>>>> Cc: Himal Prasad Ghimiray
>>>>>>>> <himal.prasad.ghimiray@intel.com>
>>>>>>>> Signed-off-by: Arvind Yadav <arvind.yadav@intel.com>
>>>>>>>> ---
>>>>>>>> drivers/gpu/drm/xe/xe_svm.c | 1 +
>>>>>>>> drivers/gpu/drm/xe/xe_vm.c | 9 ++-
>>>>>>>> drivers/gpu/drm/xe/xe_vm_madvise.c | 98
>>>>>>>> ++++++++++++++++++++++++++++--
>>>>>>>> drivers/gpu/drm/xe/xe_vm_madvise.h | 3 +
>>>>>>>> drivers/gpu/drm/xe/xe_vm_types.h | 11 ++++
>>>>>>>> 5 files changed, 116 insertions(+), 6 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/gpu/drm/xe/xe_svm.c
>>>>>>>> b/drivers/gpu/drm/xe/xe_svm.c
>>>>>>>> index cda3bf7e2418..329c77aa5c20 100644
>>>>>>>> --- a/drivers/gpu/drm/xe/xe_svm.c
>>>>>>>> +++ b/drivers/gpu/drm/xe/xe_svm.c
>>>>>>>> @@ -318,6 +318,7 @@ static void
>>>>>>>> xe_vma_set_default_attributes(struct
>>>>>>>> xe_vma *vma)
>>>>>>>> .preferred_loc.migration_policy =
>>>>>>>> DRM_XE_MIGRATE_ALL_PAGES,
>>>>>>>> .pat_index = vma-
>>>>>>>>> attr.default_pat_index,
>>>>>>>> .atomic_access =
>>>>>>>> DRM_XE_ATOMIC_UNDEFINED,
>>>>>>>> + .purgeable_state =
>>>>>>>> XE_MADV_PURGEABLE_WILLNEED,
>>>>>>>> };
>>>>>>>> xe_vma_mem_attr_copy(&vma->attr, &default_attr);
>>>>>>>> diff --git a/drivers/gpu/drm/xe/xe_vm.c
>>>>>>>> b/drivers/gpu/drm/xe/xe_vm.c
>>>>>>>> index 71cf3ce6c62b..e84b9e7cb5eb 100644
>>>>>>>> --- a/drivers/gpu/drm/xe/xe_vm.c
>>>>>>>> +++ b/drivers/gpu/drm/xe/xe_vm.c
>>>>>>>> @@ -39,6 +39,7 @@
>>>>>>>> #include "xe_tile.h"
>>>>>>>> #include "xe_tlb_inval.h"
>>>>>>>> #include "xe_trace_bo.h"
>>>>>>>> +#include "xe_vm_madvise.h"
>>>>>>>> #include "xe_wa.h"
>>>>>>>> static struct drm_gem_object *xe_vm_obj(struct xe_vm
>>>>>>>> *vm)
>>>>>>>> @@ -1085,6 +1086,7 @@ static struct xe_vma
>>>>>>>> *xe_vma_create(struct
>>>>>>>> xe_vm *vm,
>>>>>>>> static void xe_vma_destroy_late(struct xe_vma *vma)
>>>>>>>> {
>>>>>>>> struct xe_vm *vm = xe_vma_vm(vma);
>>>>>>>> + struct xe_bo *bo = xe_vma_bo(vma);
>>>>>>>> if (vma->ufence) {
>>>>>>>> xe_sync_ufence_put(vma->ufence);
>>>>>>>> @@ -1099,7 +1101,7 @@ static void
>>>>>>>> xe_vma_destroy_late(struct
>>>>>>>> xe_vma
>>>>>>>> *vma)
>>>>>>>> } else if (xe_vma_is_null(vma) ||
>>>>>>>> xe_vma_is_cpu_addr_mirror(vma)) {
>>>>>>>> xe_vm_put(vm);
>>>>>>>> } else {
>>>>>>>> - xe_bo_put(xe_vma_bo(vma));
>>>>>>>> + xe_bo_put(bo);
>>>>>>>> }
>>>>>>>> xe_vma_free(vma);
>>>>>>>> @@ -1125,6 +1127,7 @@ static void vma_destroy_cb(struct
>>>>>>>> dma_fence
>>>>>>>> *fence,
>>>>>>>> static void xe_vma_destroy(struct xe_vma *vma, struct
>>>>>>>> dma_fence
>>>>>>>> *fence)
>>>>>>>> {
>>>>>>>> struct xe_vm *vm = xe_vma_vm(vma);
>>>>>>>> + struct xe_bo *bo = xe_vma_bo(vma);
>>>>>>>> lockdep_assert_held_write(&vm->lock);
>>>>>>>> xe_assert(vm->xe, list_empty(&vma-
>>>>>>>>> combined_links.destroy));
>>>>>>>> @@ -1133,9 +1136,10 @@ static void xe_vma_destroy(struct
>>>>>>>> xe_vma *vma,
>>>>>>>> struct dma_fence *fence)
>>>>>>>> xe_assert(vm->xe, vma->gpuva.flags &
>>>>>>>> XE_VMA_DESTROYED);
>>>>>>>> xe_userptr_destroy(to_userptr_vma(vma));
>>>>>>>> } else if (!xe_vma_is_null(vma) &&
>>>>>>>> !xe_vma_is_cpu_addr_mirror(vma)) {
>>>>>>>> - xe_bo_assert_held(xe_vma_bo(vma));
>>>>>>>> + xe_bo_assert_held(bo);
>>>>>>>> drm_gpuva_unlink(&vma->gpuva);
>>>>>>>> + xe_bo_recompute_purgeable_state(bo);
>>>>>>>> }
>>>>>>>> xe_vm_assert_held(vm);
>>>>>>>> @@ -2681,6 +2685,7 @@ static int
>>>>>>>> vm_bind_ioctl_ops_parse(struct xe_vm
>>>>>>>> *vm, struct drm_gpuva_ops *ops,
>>>>>>>> .atomic_access =
>>>>>>>> DRM_XE_ATOMIC_UNDEFINED,
>>>>>>>> .default_pat_index = op-
>>>>>>>>> map.pat_index,
>>>>>>>> .pat_index = op-
>>>>>>>>> map.pat_index,
>>>>>>>> + .purgeable_state =
>>>>>>>> XE_MADV_PURGEABLE_WILLNEED,
>>>>>>>> };
>>>>>>>> flags |= op->map.vma_flags &
>>>>>>>> XE_VMA_CREATE_MASK;
>>>>>>>> diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c
>>>>>>>> b/drivers/gpu/drm/xe/xe_vm_madvise.c
>>>>>>>> index d9cfba7bfe0b..c184426546a2 100644
>>>>>>>> --- a/drivers/gpu/drm/xe/xe_vm_madvise.c
>>>>>>>> +++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
>>>>>>>> @@ -12,6 +12,7 @@
>>>>>>>> #include "xe_pat.h"
>>>>>>>> #include "xe_pt.h"
>>>>>>>> #include "xe_svm.h"
>>>>>>>> +#include "xe_vm.h"
>>>>>>>> struct xe_vmas_in_madvise_range {
>>>>>>>> u64 addr;
>>>>>>>> @@ -183,6 +184,89 @@ static void madvise_pat_index(struct
>>>>>>>> xe_device
>>>>>>>> *xe, struct xe_vm *vm,
>>>>>>>> }
>>>>>>>> }
>>>>>>>> +/**
>>>>>>>> + * xe_bo_all_vmas_dontneed() - Check if all VMAs of a BO
>>>>>>>> are
>>>>>>>> marked
>>>>>>>> DONTNEED
>>>>>>>> + * @bo: Buffer object
>>>>>>>> + *
>>>>>>>> + * Check all VMAs across all VMs to determine if BO can
>>>>>>>> be
>>>>>>>> purged.
>>>>>>>> + * Shared BOs require unanimous DONTNEED state from all
>>>>>>>> mappings.
>>>>>>>> + *
>>>>>>>> + * Caller must hold BO dma-resv lock.
>>>>>>>> + *
>>>>>>>> + * Return: true if all VMAs are DONTNEED, false
>>>>>>>> otherwise
>>>>>>>> + */
>>>>>>>> +static bool xe_bo_all_vmas_dontneed(struct xe_bo *bo)
>>>>>>>> +{
>>>>>>>> + struct drm_gpuvm_bo *vm_bo;
>>>>>>>> + struct drm_gpuva *gpuva;
>>>>>>>> + struct drm_gem_object *obj = &bo->ttm.base;
>>>>>>>> + bool has_vmas = false;
>>>>>>>> +
>>>>>>>> + xe_bo_assert_held(bo);
>>>>>>>> +
>>>>>>>> + drm_gem_for_each_gpuvm_bo(vm_bo, obj) {
>>>>>>>> + drm_gpuvm_bo_for_each_va(gpuva, vm_bo) {
>>>>>>>> + struct xe_vma *vma =
>>>>>>>> gpuva_to_vma(gpuva);
>>>>>>>> +
>>>>>>>> + has_vmas = true;
>>>>>>>> +
>>>>>>>> + /* Any non-DONTNEED VMA prevents
>>>>>>>> purging */
>>>>>>>> + if (vma->attr.purgeable_state !=
>>>>>>>> XE_MADV_PURGEABLE_DONTNEED)
>>>>>>>> + return false;
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + /*
>>>>>>>> + * No VMAs => no mapping-level DONTNEED hint.
>>>>>>>> + * Default to WILLNEED to avoid making BOs
>>>>>>>> purgeable
>>>>>>>> without
>>>>>>>> + * explicit user intent.
>>>>>>>> + */
>>>>>>>> + if (!has_vmas)
>>>>>>>> + return false;
>>>>>>>> +
>>>>>>>> + return true;
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> +/**
>>>>>>>> + * xe_bo_recompute_purgeable_state() - Recompute BO
>>>>>>>> purgeable state
>>>>>>>> from VMAs
>>>>>>>> + * @bo: Buffer object
>>>>>>>> + *
>>>>>>>> + * Walk all VMAs to determine if BO should be purgeable
>>>>>>>> or
>>>>>>>> not.
>>>>>>>> + * Shared BOs require unanimous DONTNEED state from all
>>>>>>>> mappings.
>>>>>>>> + *
>>>>>>>> + * Locking: Caller must hold BO dma-resv lock. When
>>>>>>>> iterating GPUVM
>>>>>>>> lists,
>>>>>>>> + * VM lock must also be held (write) to prevent
>>>>>>>> concurrent
>>>>>>>> VMA
>>>>>>>> modifications.
>>>>>>>> + * This is satisfied at both call sites:
>>>>>>>> + * - xe_vma_destroy(): holds vm->lock write
>>>>>>>> + * - madvise_purgeable(): holds vm->lock write (from
>>>>>>>> madvise
>>>>>>>> ioctl
>>>>>>>> path)
>>>>>>>> + *
>>>>>>>> + * Return: nothing
>>>>>>>> + */
>>>>>>>> +void xe_bo_recompute_purgeable_state(struct xe_bo *bo)
>>>>>>>> +{
>>>>>>>> + if (!bo)
>>>>>>>> + return;
>>>>>>>> +
>>>>>>>> + xe_bo_assert_held(bo);
>>>>>>>> +
>>>>>>>> + /*
>>>>>>>> + * Once purged, always purged. Cannot transition
>>>>>>>> back to
>>>>>>>> WILLNEED.
>>>>>>>> + * This matches i915 semantics where purged BOs
>>>>>>>> are
>>>>>>>> permanently invalid.
>>>>>>>> + */
>>>>>>>> + if (bo->madv_purgeable ==
>>>>>>>> XE_MADV_PURGEABLE_PURGED)
>>>>>>>> + return;
>>>>>>>> +
>>>>>>>> + if (xe_bo_all_vmas_dontneed(bo)) {
>>>>>>>> + /* All VMAs are DONTNEED - mark BO
>>>>>>>> purgeable
>>>>>>>> */
>>>>>>>> + if (bo->madv_purgeable !=
>>>>>>>> XE_MADV_PURGEABLE_DONTNEED)
>>>>>>>> + xe_bo_set_purgeable_state(bo,
>>>>>>>> XE_MADV_PURGEABLE_DONTNEED);
>>>>>>>> + } else {
>>>>>>>> + /* At least one VMA is WILLNEED - BO
>>>>>>>> must
>>>>>>>> not be
>>>>>>>> purgeable */
>>>>>>>> + if (bo->madv_purgeable !=
>>>>>>>> XE_MADV_PURGEABLE_WILLNEED)
>>>>>>>> + xe_bo_set_purgeable_state(bo,
>>>>>>>> XE_MADV_PURGEABLE_WILLNEED);
>>>>>>>> + }
>>>>>>>> +}
>>>>>>>> +
>>>>>>>> /**
>>>>>>>> * madvise_purgeable - Handle purgeable buffer object
>>>>>>>> advice
>>>>>>>> * @xe: XE device
>>>>>>>> @@ -231,14 +315,20 @@ static void __maybe_unused
>>>>>>>> madvise_purgeable(struct xe_device *xe,
>>>>>>>> switch (op->purge_state_val.val) {
>>>>>>>> case
>>>>>>>> DRM_XE_VMA_PURGEABLE_STATE_WILLNEED:
>>>>>>>> - xe_bo_set_purgeable_state(bo,
>>>>>>>> XE_MADV_PURGEABLE_WILLNEED);
>>>>>>>> + vmas[i]->attr.purgeable_state =
>>>>>>>> XE_MADV_PURGEABLE_WILLNEED;
>>>>>>>> +
>>>>>>>> + /* Update BO purgeable state */
>>>>>>>> + xe_bo_recompute_purgeable_state(
>>>>>>>> bo);
>>>>>>>> break;
>>>>>>>> case
>>>>>>>> DRM_XE_VMA_PURGEABLE_STATE_DONTNEED:
>>>>>>>> - xe_bo_set_purgeable_state(bo,
>>>>>>>> XE_MADV_PURGEABLE_DONTNEED);
>>>>>>>> + vmas[i]->attr.purgeable_state =
>>>>>>>> XE_MADV_PURGEABLE_DONTNEED;
>>>>>>>> +
>>>>>>>> + /* Update BO purgeable state */
>>>>>>>> + xe_bo_recompute_purgeable_state(
>>>>>>>> bo);
>>>>>>>> break;
>>>>>>>> default:
>>>>>>>> - drm_warn(&vm->xe->drm, "Invalid
>>>>>>>> madvice
>>>>>>>> value = %d\n",
>>>>>>>> - op-
>>>>>>>>> purge_state_val.val);
>>>>>>>> + /* Should never hit - values
>>>>>>>> validated in
>>>>>>>> madvise_args_are_sane() */
>>>>>>>> + xe_assert(vm->xe, 0);
>>>>>>>> return;
>>>>>>>> }
>>>>>>>> }
>>>>>>>> diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.h
>>>>>>>> b/drivers/gpu/drm/xe/xe_vm_madvise.h
>>>>>>>> index b0e1fc445f23..39acd2689ca0 100644
>>>>>>>> --- a/drivers/gpu/drm/xe/xe_vm_madvise.h
>>>>>>>> +++ b/drivers/gpu/drm/xe/xe_vm_madvise.h
>>>>>>>> @@ -8,8 +8,11 @@
>>>>>>>> struct drm_device;
>>>>>>>> struct drm_file;
>>>>>>>> +struct xe_bo;
>>>>>>>> int xe_vm_madvise_ioctl(struct drm_device *dev, void
>>>>>>>> *data,
>>>>>>>> struct drm_file *file);
>>>>>>>> +void xe_bo_recompute_purgeable_state(struct xe_bo *bo);
>>>>>>>> +
>>>>>>>> #endif
>>>>>>>> diff --git a/drivers/gpu/drm/xe/xe_vm_types.h
>>>>>>>> b/drivers/gpu/drm/xe/xe_vm_types.h
>>>>>>>> index 43203e90ee3e..fd563039e8f4 100644
>>>>>>>> --- a/drivers/gpu/drm/xe/xe_vm_types.h
>>>>>>>> +++ b/drivers/gpu/drm/xe/xe_vm_types.h
>>>>>>>> @@ -94,6 +94,17 @@ struct xe_vma_mem_attr {
>>>>>>>> * same as default_pat_index unless overwritten
>>>>>>>> by
>>>>>>>> madvise.
>>>>>>>> */
>>>>>>>> u16 pat_index;
>>>>>>>> +
>>>>>>>> + /**
>>>>>>>> + * @purgeable_state: Purgeable hint for this VMA
>>>>>>>> mapping
>>>>>>>> + *
>>>>>>>> + * Per-VMA purgeable state from madvise. Valid
>>>>>>>> states are
>>>>>>>> WILLNEED (0)
>>>>>>>> + * or DONTNEED (1). Shared BOs require all VMAs
>>>>>>>> to
>>>>>>>> be
>>>>>>>> DONTNEED before
>>>>>>>> + * the BO can be purged. PURGED state exists
>>>>>>>> only at
>>>>>>>> BO
>>>>>>>> level.
>>>>>>>> + *
>>>>>>>> + * Protected by BO dma-resv lock. Set via
>>>>>>>> DRM_IOCTL_XE_MADVISE.
>>>>>>>> + */
>>>>>>>> + u32 purgeable_state;
>>>>>>>> };
>>>>>>>> struct xe_vma {
next prev parent reply other threads:[~2026-02-25 9:41 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-11 15:26 [PATCH v5 0/9] drm/xe/madvise: Add support for purgeable buffer objects Arvind Yadav
2026-02-11 15:26 ` [PATCH v5 1/9] drm/xe/uapi: Add UAPI " Arvind Yadav
2026-02-24 10:50 ` Thomas Hellström
2026-02-26 17:58 ` Souza, Jose
2026-02-27 9:32 ` Yadav, Arvind
2026-02-11 15:26 ` [PATCH v5 2/9] drm/xe/bo: Add purgeable bo state tracking and field madv to xe_bo Arvind Yadav
2026-02-11 16:00 ` Matthew Brost
2026-02-11 15:26 ` [PATCH v5 3/9] drm/xe/madvise: Implement purgeable buffer object support Arvind Yadav
2026-02-24 12:21 ` Thomas Hellström
2026-02-24 14:56 ` Yadav, Arvind
2026-02-11 15:26 ` [PATCH v5 4/9] drm/xe/bo: Handle CPU faults on purged buffer objects Arvind Yadav
2026-02-11 15:26 ` [PATCH v5 5/9] drm/xe/vm: Prevent binding of " Arvind Yadav
2026-02-11 16:17 ` Matthew Brost
2026-02-11 15:26 ` [PATCH v5 6/9] drm/xe/madvise: Implement per-VMA purgeable state tracking Arvind Yadav
2026-02-24 12:48 ` Thomas Hellström
2026-02-24 15:07 ` Yadav, Arvind
2026-02-24 16:36 ` Matthew Brost
2026-02-25 5:35 ` Yadav, Arvind
2026-02-25 8:21 ` Thomas Hellström
2026-02-25 9:04 ` Matthew Brost
2026-02-25 9:18 ` Thomas Hellström
2026-02-25 9:40 ` Yadav, Arvind [this message]
2026-02-25 18:32 ` Matthew Brost
2026-02-11 15:26 ` [PATCH v5 7/9] drm/xe/madvise: Block imported and exported dma-bufs Arvind Yadav
2026-02-24 14:15 ` Thomas Hellström
2026-02-11 15:26 ` [PATCH v5 8/9] drm/xe/bo: Add purgeable shrinker state helpers Arvind Yadav
2026-02-24 14:21 ` Thomas Hellström
2026-02-24 15:09 ` Yadav, Arvind
2026-02-11 15:26 ` [PATCH v5 9/9] drm/xe/madvise: Enable purgeable buffer object IOCTL support Arvind Yadav
2026-02-11 15:40 ` Matthew Brost
2026-02-11 15:46 ` [PATCH v5 0/9] drm/xe/madvise: Add support for purgeable buffer objects Matthew Brost
2026-02-25 10:10 ` Yadav, Arvind
2026-02-11 16:21 ` ✗ CI.checkpatch: warning for drm/xe/madvise: Add support for purgeable buffer objects (rev6) Patchwork
2026-02-11 16:22 ` ✓ CI.KUnit: success " Patchwork
2026-02-11 17:11 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-02-13 1:15 ` ✗ Xe.CI.FULL: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=02b79322-f378-4e4f-befc-3f9bba9f7830@intel.com \
--to=arvind.yadav@intel.com \
--cc=himal.prasad.ghimiray@intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=matthew.brost@intel.com \
--cc=pallavi.mishra@intel.com \
--cc=thomas.hellstrom@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox