Re: [PATCH v6 01/12] drm/xe/uapi: Add UAPI support for purgeable buffer objects

Yadav, Arvind
2026-03-20T04:00:29Z

On 03-03-2026 21:23, Souza, Jose wrote:
> On Tue, 2026-03-03 at 20:49 +0530, Arvind Yadav wrote:
>> From: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
>>
>> Extend the DRM_XE_MADVISE ioctl to support purgeable buffer object
>> management by adding DRM_XE_VMA_ATTR_PURGEABLE_STATE attribute type.
>>
>> This allows userspace applications to provide memory usage hints to
>> the kernel for better memory management under pressure:
>>
>> - WILLNEED: Buffer is needed and should not be purged. If the BO was
>>   previously purged, retained field returns 0 indicating backing
>> store
>>   was lost (once purged, always purged semantics matching i915).
>>
>> - DONTNEED: Buffer is not currently needed and may be purged by the
>>   kernel under memory pressure to free resources. Only applies to
>>   non-shared BOs.
>>
>>   To prevent undefined behavior, the following operations are blocked
>>   while a BO is in DONTNEED state:
>>   - New mmap() operations return -EBUSY
>>   - VM_BIND operations return -EBUSY
>>   - New dma-buf exports return -EBUSY
>>   - CPU page faults return SIGBUS
>>   - GPU page faults fail with -EACCES
>>
>>   This ensures applications cannot use a BO while marked as DONTNEED,
>>   preventing erratic behavior when the kernel purges the backing
>> store.
>>
>> The implementation includes a 'retained' output field (matching
>> i915's
>> drm_i915_gem_madvise.retained) that indicates whether the BO's
>> backing
>> store still exists (1) or has been purged (0).
>>
>> Added DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT flag to allow
>> userspace to detect kernel support for purgeable buffer objects
>> before attempting to use the feature.
>>
>> v2:
>>   - Add PURGED state for read-only status, change ioctl to DRM_IOWR,
>>     add retained field for i915 compatibility
>>
>> v3:
>>   - UAPI rule should not be changed (Matthew Brost)
>>   - Make 'retained' a userptr (Matthew Brost)
>>
>> v4:
>>   - You cannot make this part of the union (purge_state_val) larger
>>     than the existing union (16 bytes). So just drop the '__u64
>> reserved'
>>     field. (Matt)
>>
>> v5:
>>   - Update UAPI documentation to clarify retained must be initialized
>>     to 0(Thomas)
>>
>> v6:
>>   - Document DONTNEED BO access blocking behavior to prevent
>> undefined
>>     behavior and clarify uAPI contract (Thomas, Matt)
>>   - Add query flag DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT for
>>     feature detection. (Jose)
>>   - Rename retained to retained_ptr. (Jose)
>>
>> Cc: Jose Souze <jose.souza@intel.com>
>> Cc: Matthew Brost <matthew.brost@intel.com>
>> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
>> Signed-off-by: Himal Prasad Ghimiray
>> <himal.prasad.ghimiray@intel.com>
>> Signed-off-by: Arvind Yadav <arvind.yadav@intel.com>
>> ---
>>  include/uapi/drm/xe_drm.h | 60
>> +++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 60 insertions(+)
>>
>> diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h
>> index ef2565048bdf..42aedd30189d 100644
>> --- a/include/uapi/drm/xe_drm.h
>> +++ b/include/uapi/drm/xe_drm.h
>> @@ -425,6 +425,7 @@ struct drm_xe_query_config {
>>   #define DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY (1
>> << 1)
>>   #define DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR (1
>> << 2)
>>   #define DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT (1
>> << 3)
>> + #define DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT (1
>> << 4)
>>  #define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT 2
>>  #define DRM_XE_QUERY_CONFIG_VA_BITS 3
>>  #define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY 4
>> @@ -2067,6 +2068,7 @@ struct drm_xe_query_eu_stall {
>>   *  - DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC: Set preferred memory
>> location.
>>   *  - DRM_XE_MEM_RANGE_ATTR_ATOMIC: Set atomic access policy.
>>   *  - DRM_XE_MEM_RANGE_ATTR_PAT: Set page attribute table index.
>> + *  - DRM_XE_VMA_ATTR_PURGEABLE_STATE: Set purgeable state for BOs.
>>   *
>>   * Example:
>>   *
>> @@ -2099,6 +2101,7 @@ struct drm_xe_madvise {
>>  #define DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC 0
>>  #define DRM_XE_MEM_RANGE_ATTR_ATOMIC 1
>>  #define DRM_XE_MEM_RANGE_ATTR_PAT 2
>> +#define DRM_XE_VMA_ATTR_PURGEABLE_STATE 3
>>   /** @type: type of attribute */
>>   __u32 type;
>>
>> @@ -2189,6 +2192,63 @@ struct drm_xe_madvise {
>>   /** @pat_index.reserved: Reserved */
>>   __u64 reserved;
>>   } pat_index;
>> +
>> + /**
>> + * @purge_state_val: Purgeable state configuration
>> + *
>> + * Used when @type ==
>> DRM_XE_VMA_ATTR_PURGEABLE_STATE.
>> + *
>> + * Configures the purgeable state of buffer objects
>> in the specified
>> + * virtual address range. This allows applications
>> to hint to the kernel
>> + * about bo's usage patterns for better memory
>> management.
>> + *
>> + * Supported values for @purge_state_val.val:
>> + *  - DRM_XE_VMA_PURGEABLE_STATE_WILLNEED (0): Marks
>> BO as needed.
>> + *    If BO was previously purged, returns
>> retained=0 (backing store lost).
>> + *
>> + *  - DRM_XE_VMA_PURGEABLE_STATE_DONTNEED (1): Marks
>> BO as not currently
>> + *    needed. Kernel may purge it under memory
>> pressure to reclaim memory.
>> + *    Only applies to non-shared BOs. Returns
>> retained=1 if not purged yet.
> Nothing is returned, I think this need to be updated to reflect that
> the backing store is updated to 1, same in
> DRM_XE_VMA_PURGEABLE_STATE_WILLNEED.

Noted,

>
>> + *
>> + *    Important: Once marked as DONTNEED, touching
>> the BO's memory
>> + *    is undefined behavior. It may succeed
>> temporarily (before the
>> + *    kernel purges the backing store) but will
>> suddenly fail once
>> + *    the BO transitions to PURGED state.
> Just to make sure I understood correctly, if I want to change from
> DONTNEED to WILLNEED, I do the uAPI call and then check if the backing
> storage is set to 1?

Yes, correct. Call the ioctl with WILLNEED and then check the __u32 at
@retained_ptr: if it's 0 the backing store was lost and the BO must be
recreated. Added an explicit paragraph explaining this flow.

> By default all VMAs are in WILLNEED state right?

Yes. By default all VMAs are in WILLNEED state.

Thanks,
Arvind

>
>> + *
>> + *    The following operations are blocked in
>> DONTNEED state to
>> + *    prevent the BO from being re-mapped after
>> madvise:
>> + *    - New mmap() calls: Fail with -EBUSY
>> + *    - VM_BIND operations: Fail with -EBUSY
>> + *    - New dma-buf exports: Fail with -EBUSY
>> + *    - CPU page faults (existing mmap): Fail with
>> SIGBUS
>> + *    - GPU page faults (fault-mode VMs): Fail with
>> -EACCES
>> + */
>> + struct {
>> +#define DRM_XE_VMA_PURGEABLE_STATE_WILLNEED 0
>> +#define DRM_XE_VMA_PURGEABLE_STATE_DONTNEED 1
>> + /** @purge_state_val.val: value for
>> DRM_XE_VMA_ATTR_PURGEABLE_STATE */
>> + __u32 val;
>> +
>> + /** @purge_state_val.pad: MBZ */
>> + __u32 pad;
>> + /**
>> + * @purge_state_val.retained_ptr: Pointer to
>> a __u32 output
>> + * field for backing store status.
>> + *
>> + * Userspace must initialize the __u32 value
>> at this address
>> + * to 0 before the ioctl. Kernel writes a
>> __u32 after the
>> + * operation:
>> + * - 1 if backing store exists (not purged)
>> + * - 0 if backing store was purged
>> + *
>> + * If userspace fails to initialize to 0,
>> ioctl returns -EINVAL.
>> + * This ensures a safe default (0 = assume
>> purged) if kernel
>> + * cannot write the result.
>> + *
>> + * Similar to i915's
>> drm_i915_gem_madvise.retained field.
>> + */
>> + __u64 retained_ptr;
>> + } purge_state_val;
>>   };
>>
>>   /** @reserved: Reserved */