History

Merge tag 'drm-xe-next-2026-03-26-1' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next

Hi Dave and Sima, Here goes our late, final drm-xe-next PR towards 7.1. We just purgeable BO uAPI in today, hence the late pull. In the big things we have: - Add support for purgeable buffer objects Thanks, Matt UAPI Changes: - Add support for purgeable buffer objects (Arvind, Himal) Driver Changes: - Remove useless comment (Maarten) - Issue GGTT invalidation under lock in ggtt_node_remove (Brost, Fixes) - Fix mismatched include guards in header files (Shuicheng)

Dave Airlie committed 7 months ago

Commit a51973c2 parents 0d270f0 05c8b1c22 files · +814 −68Browse files

Unified · Split

22 files
  1. drivers/gpu/drm/xe/xe_bo.c +181 −13
  2. drivers/gpu/drm/xe/xe_bo.h +58 −0
  3. drivers/gpu/drm/xe/xe_bo_types.h +6 −0
  4. drivers/gpu/drm/xe/xe_device.c +0 −3
  5. drivers/gpu/drm/xe/xe_dma_buf.c +24 −0
  6. drivers/gpu/drm/xe/xe_ggtt.c +2 −7
  7. drivers/gpu/drm/xe/xe_gt_idle_types.h +3 −3
  8. drivers/gpu/drm/xe/xe_guc_exec_queue_types.h +2 −2
  9. drivers/gpu/drm/xe/xe_heci_gsc.h +3 −3
  10. drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.h +2 −2
  11. drivers/gpu/drm/xe/xe_late_bind_fw_types.h +2 −2
  12. drivers/gpu/drm/xe/xe_pagefault.c +14 −1
  13. drivers/gpu/drm/xe/xe_platform_types.h +2 −2
  14. drivers/gpu/drm/xe/xe_pt.c +33 −7
  15. drivers/gpu/drm/xe/xe_query.c +2 −0
  16. drivers/gpu/drm/xe/xe_svm.c +1 −0
  17. drivers/gpu/drm/xe/xe_tile_printk.h +2 −2
  18. drivers/gpu/drm/xe/xe_vm.c +95 −17
  19. drivers/gpu/drm/xe/xe_vm_madvise.c +299 −4
  20. drivers/gpu/drm/xe/xe_vm_madvise.h +3 −0
  21. drivers/gpu/drm/xe/xe_vm_types.h +11 −0
  22. include/uapi/drm/xe_drm.h +69 −0
drivers/gpu/drm/xe/xe_bo.c+181−13
@@ -838,6 +838,122 @@ static int xe_bo_move_notify(struct xe_bo *bo, · 837 unmodified lines
838 return 0;838 return 0;
839}839}
840 840
841/**
842 * xe_bo_set_purgeable_shrinker() - Update shrinker accounting for purgeable state
843 * @bo: Buffer object
844 * @new_state: New purgeable state being set
845 *
846 * Transfers pages between shrinkable and purgeable buckets when the BO
847 * purgeable state changes. Called automatically from xe_bo_set_purgeable_state().
848 */
849static void xe_bo_set_purgeable_shrinker(struct xe_bo *bo,
850 enum xe_madv_purgeable_state new_state)
851{
852 struct ttm_buffer_object *ttm_bo = &bo->ttm;
853 struct ttm_tt *tt = ttm_bo->ttm;
854 struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev);
855 struct xe_ttm_tt *xe_tt;
856 long tt_pages;
857
858 xe_bo_assert_held(bo);
859
860 if (!tt || !ttm_tt_is_populated(tt))
861 return;
862
863 xe_tt = container_of(tt, struct xe_ttm_tt, ttm);
864 tt_pages = tt->num_pages;
865
866 if (!xe_tt->purgeable && new_state == XE_MADV_PURGEABLE_DONTNEED) {
867 xe_tt->purgeable = true;
868 /* Transfer pages from shrinkable to purgeable count */
869 xe_shrinker_mod_pages(xe->mem.shrinker, -tt_pages, tt_pages);
870 } else if (xe_tt->purgeable && new_state == XE_MADV_PURGEABLE_WILLNEED) {
871 xe_tt->purgeable = false;
872 /* Transfer pages from purgeable to shrinkable count */
873 xe_shrinker_mod_pages(xe->mem.shrinker, tt_pages, -tt_pages);
874 }
875}
876
877/**
878 * xe_bo_set_purgeable_state() - Set BO purgeable state with validation
879 * @bo: Buffer object
880 * @new_state: New purgeable state
881 *
882 * Sets the purgeable state with lockdep assertions and validates state
883 * transitions. Once a BO is PURGED, it cannot transition to any other state.
884 * Invalid transitions are caught with xe_assert(). Shrinker page accounting
885 * is updated automatically.
886 */
887void xe_bo_set_purgeable_state(struct xe_bo *bo,
888 enum xe_madv_purgeable_state new_state)
889{
890 struct xe_device *xe = xe_bo_device(bo);
891
892 xe_bo_assert_held(bo);
893
894 /* Validate state is one of the known values */
895 xe_assert(xe, new_state == XE_MADV_PURGEABLE_WILLNEED ||
896 new_state == XE_MADV_PURGEABLE_DONTNEED ||
897 new_state == XE_MADV_PURGEABLE_PURGED);
898
899 /* Once purged, always purged - cannot transition out */
900 xe_assert(xe, !(bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED &&
901 new_state != XE_MADV_PURGEABLE_PURGED));
902
903 bo->madv_purgeable = new_state;
904 xe_bo_set_purgeable_shrinker(bo, new_state);
905}
906
907/**
908 * xe_ttm_bo_purge() - Purge buffer object backing store
909 * @ttm_bo: The TTM buffer object to purge
910 * @ctx: TTM operation context
911 *
912 * This function purges the backing store of a BO marked as DONTNEED and
913 * triggers rebind to invalidate stale GPU mappings. For fault-mode VMs,
914 * this zaps the PTEs. The next GPU access will trigger a page fault and
915 * perform NULL rebind (scratch pages or clear PTEs based on VM config).
916 *
917 * Return: 0 on success, negative error code on failure
918 */
919static int xe_ttm_bo_purge(struct ttm_buffer_object *ttm_bo, struct ttm_operation_ctx *ctx)
920{
921 struct xe_bo *bo = ttm_to_xe_bo(ttm_bo);
922 struct ttm_placement place = {};
923 int ret;
924
925 xe_bo_assert_held(bo);
926
927 if (!ttm_bo->ttm)
928 return 0;
929
930 if (!xe_bo_madv_is_dontneed(bo))
931 return 0;
932
933 /*
934 * Use the standard pre-move hook so we share the same cleanup/invalidate
935 * path as migrations: drop any CPU vmap and schedule the necessary GPU
936 * unbind/rebind work.
937 *
938 * This must be called before ttm_bo_validate() frees the pages.
939 * May fail in no-wait contexts (fault/shrinker) or if the BO is
940 * pinned. Keep state unchanged on failure so we don't end up "PURGED"
941 * with stale mappings.
942 */
943 ret = xe_bo_move_notify(bo, ctx);
944 if (ret)
945 return ret;
946
947 ret = ttm_bo_validate(ttm_bo, &place, ctx);
948 if (ret)
949 return ret;
950
951 /* Commit the state transition only once invalidation was queued */
952 xe_bo_set_purgeable_state(bo, XE_MADV_PURGEABLE_PURGED);
953
954 return 0;
955}
956
841static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,957static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
842 struct ttm_operation_ctx *ctx,958 struct ttm_operation_ctx *ctx,
843 struct ttm_resource *new_mem,959 struct ttm_resource *new_mem,
@@ -857,6 +973,20 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, · 13 unmodified lines
857 ttm && ttm_tt_is_populated(ttm)) ? true : false;973 ttm && ttm_tt_is_populated(ttm)) ? true : false;
858 int ret = 0;974 int ret = 0;
859 975
976 /*
977 * Purge only non-shared BOs explicitly marked DONTNEED by userspace.
978 * The move_notify callback will handle invalidation asynchronously.
979 */
980 if (evict && xe_bo_madv_is_dontneed(bo)) {
981 ret = xe_ttm_bo_purge(ttm_bo, ctx);
982 if (ret)
983 return ret;
984
985 /* Free the unused eviction destination resource */
986 ttm_resource_free(ttm_bo, &new_mem);
987 return 0;
988 }
989
860 /* Bo creation path, moving to system or TT. */990 /* Bo creation path, moving to system or TT. */
861 if ((!old_mem && ttm) && !handle_system_ccs) {991 if ((!old_mem && ttm) && !handle_system_ccs) {
862 if (new_mem->mem_type == XE_PL_TT)992 if (new_mem->mem_type == XE_PL_TT)
@@ -1154,6 +1284,9 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo, · 291 unmodified lines
1154 lret = xe_bo_move_notify(xe_bo, ctx);1284 lret = xe_bo_move_notify(xe_bo, ctx);
1155 if (!lret)1285 if (!lret)
1156 lret = xe_bo_shrink_purge(ctx, bo, scanned);1286 lret = xe_bo_shrink_purge(ctx, bo, scanned);
1287 if (lret > 0 && xe_bo_madv_is_dontneed(xe_bo))
1288 xe_bo_set_purgeable_state(xe_bo,
1289 XE_MADV_PURGEABLE_PURGED);
1157 goto out_unref;1290 goto out_unref;
1158 }1291 }
1159 1292
@@ -1606,18 +1739,6 @@ static void xe_ttm_bo_delete_mem_notify(struct ttm_buffer_object *ttm_bo) · 446 unmodified lines
1606 }1739 }
1607}1740}
1608 1741
1609static void xe_ttm_bo_purge(struct ttm_buffer_object *ttm_bo, struct ttm_operation_ctx *ctx)
1610{
1611 struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev);
1612
1613 if (ttm_bo->ttm) {
1614 struct ttm_placement place = {};
1615 int ret = ttm_bo_validate(ttm_bo, &place, ctx);
1616
1617 drm_WARN_ON(&xe->drm, ret);
1618 }
1619}
1620
1621static void xe_ttm_bo_swap_notify(struct ttm_buffer_object *ttm_bo)1742static void xe_ttm_bo_swap_notify(struct ttm_buffer_object *ttm_bo)
1622{1743{
1623 struct ttm_operation_ctx ctx = {1744 struct ttm_operation_ctx ctx = {
@@ -1902,6 +2023,16 @@ static vm_fault_t xe_bo_cpu_fault_fastpath(struct vm_fault *vmf, struct xe_devic · 278 unmodified lines
1902 if (!dma_resv_trylock(tbo->base.resv))2023 if (!dma_resv_trylock(tbo->base.resv))
1903 goto out_validation;2024 goto out_validation;
1904 2025
2026 /*
2027 * Reject CPU faults to purgeable BOs. DONTNEED BOs can be purged
2028 * at any time, and purged BOs have no backing store. Either case
2029 * is undefined behavior for CPU access.
2030 */
2031 if (xe_bo_madv_is_dontneed(bo) || xe_bo_is_purged(bo)) {
2032 ret = VM_FAULT_SIGBUS;
2033 goto out_unlock;
2034 }
2035
1905 if (xe_ttm_bo_is_imported(tbo)) {2036 if (xe_ttm_bo_is_imported(tbo)) {
1906 ret = VM_FAULT_SIGBUS;2037 ret = VM_FAULT_SIGBUS;
1907 drm_dbg(&xe->drm, "CPU trying to access an imported buffer object.\n");2038 drm_dbg(&xe->drm, "CPU trying to access an imported buffer object.\n");
@@ -1992,6 +2123,15 @@ static vm_fault_t xe_bo_cpu_fault(struct vm_fault *vmf) · 84 unmodified lines
1992 if (err)2123 if (err)
1993 break;2124 break;
1994 2125
2126 /*
2127 * Reject CPU faults to purgeable BOs. DONTNEED BOs can be
2128 * purged at any time, and purged BOs have no backing store.
2129 */
2130 if (xe_bo_madv_is_dontneed(bo) || xe_bo_is_purged(bo)) {
2131 err = -EFAULT;
2132 break;
2133 }
2134
1995 if (xe_ttm_bo_is_imported(tbo)) {2135 if (xe_ttm_bo_is_imported(tbo)) {
1996 err = -EFAULT;2136 err = -EFAULT;
1997 drm_dbg(&xe->drm, "CPU trying to access an imported buffer object.\n");2137 drm_dbg(&xe->drm, "CPU trying to access an imported buffer object.\n");
@@ -2069,10 +2209,35 @@ static const struct vm_operations_struct xe_gem_vm_ops = { · 71 unmodified lines
2069 .access = xe_bo_vm_access,2209 .access = xe_bo_vm_access,
2070};2210};
2071 2211
2212static int xe_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
2213{
2214 struct xe_bo *bo = gem_to_xe_bo(obj);
2215 int err = 0;
2216
2217 /*
2218 * Reject mmap of purgeable BOs. DONTNEED BOs can be purged
2219 * at any time, making CPU access undefined behavior. Purged BOs have
2220 * no backing store and are permanently invalid.
2221 */
2222 err = xe_bo_lock(bo, true);
2223 if (err)
2224 return err;
2225
2226 if (xe_bo_madv_is_dontneed(bo))
2227 err = -EBUSY;
2228 else if (xe_bo_is_purged(bo))
2229 err = -EINVAL;
2230 xe_bo_unlock(bo);
2231 if (err)
2232 return err;
2233
2234 return drm_gem_ttm_mmap(obj, vma);
2235}
2236
2072static const struct drm_gem_object_funcs xe_gem_object_funcs = {2237static const struct drm_gem_object_funcs xe_gem_object_funcs = {
2073 .free = xe_gem_object_free,2238 .free = xe_gem_object_free,
2074 .close = xe_gem_object_close,2239 .close = xe_gem_object_close,
2075 .mmap = drm_gem_ttm_mmap,2240 .mmap = xe_gem_object_mmap,
2076 .export = xe_gem_prime_export,2241 .export = xe_gem_prime_export,
2077 .vm_ops = &xe_gem_vm_ops,2242 .vm_ops = &xe_gem_vm_ops,
2078};2243};
@@ -2198,6 +2363,9 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo, · 119 unmodified lines
2198#endif2363#endif
2199 INIT_LIST_HEAD(&bo->vram_userfault_link);2364 INIT_LIST_HEAD(&bo->vram_userfault_link);
2200 2365
2366 /* Initialize purge advisory state */
2367 bo->madv_purgeable = XE_MADV_PURGEABLE_WILLNEED;
2368
2201 drm_gem_private_object_init(&xe->drm, &bo->ttm.base, size);2369 drm_gem_private_object_init(&xe->drm, &bo->ttm.base, size);
2202 2370
2203 if (resv) {2371 if (resv) {
drivers/gpu/drm/xe/xe_bo.h+58−0
@@ -87,6 +87,28 @@ · 86 unmodified lines
87 87
88#define XE_PCI_BARRIER_MMAP_OFFSET (0x50 << XE_PTE_SHIFT)88#define XE_PCI_BARRIER_MMAP_OFFSET (0x50 << XE_PTE_SHIFT)
89 89
90/**
91 * enum xe_madv_purgeable_state - Buffer object purgeable state enumeration
92 *
93 * This enum defines the possible purgeable states for a buffer object,
94 * allowing userspace to provide memory usage hints to the kernel for
95 * better memory management under pressure.
96 *
97 * @XE_MADV_PURGEABLE_WILLNEED: The buffer object is needed and should not be purged.
98 * This is the default state.
99 * @XE_MADV_PURGEABLE_DONTNEED: The buffer object is not currently needed and can be
100 * purged by the kernel under memory pressure.
101 * @XE_MADV_PURGEABLE_PURGED: The buffer object has been purged by the kernel.
102 *
103 * Accessing a purged buffer will result in an error. Per i915 semantics,
104 * once purged, a BO remains permanently invalid and must be destroyed and recreated.
105 */
106enum xe_madv_purgeable_state {
107 XE_MADV_PURGEABLE_WILLNEED,
108 XE_MADV_PURGEABLE_DONTNEED,
109 XE_MADV_PURGEABLE_PURGED,
110};
111
90struct sg_table;112struct sg_table;
91 113
92struct xe_bo *xe_bo_alloc(void);114struct xe_bo *xe_bo_alloc(void);
@@ -215,6 +237,42 @@ static inline bool xe_bo_is_protected(const struct xe_bo *bo) · 122 unmodified lines
215 return bo->pxp_key_instance;237 return bo->pxp_key_instance;
216}238}
217 239
240/**
241 * xe_bo_is_purged() - Check if buffer object has been purged
242 * @bo: The buffer object to check
243 *
244 * Checks if the buffer object's backing store has been discarded by the
245 * kernel due to memory pressure after being marked as purgeable (DONTNEED).
246 * Once purged, the BO cannot be restored and any attempt to use it will fail.
247 *
248 * Context: Caller must hold the BO's dma-resv lock
249 * Return: true if the BO has been purged, false otherwise
250 */
251static inline bool xe_bo_is_purged(struct xe_bo *bo)
252{
253 xe_bo_assert_held(bo);
254 return bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED;
255}
256
257/**
258 * xe_bo_madv_is_dontneed() - Check if BO is marked as DONTNEED
259 * @bo: The buffer object to check
260 *
261 * Checks if userspace has marked this BO as DONTNEED (i.e., its contents
262 * are not currently needed and can be discarded under memory pressure).
263 * This is used internally to decide whether a BO is eligible for purging.
264 *
265 * Context: Caller must hold the BO's dma-resv lock
266 * Return: true if the BO is marked DONTNEED, false otherwise
267 */
268static inline bool xe_bo_madv_is_dontneed(struct xe_bo *bo)
269{
270 xe_bo_assert_held(bo);
271 return bo->madv_purgeable == XE_MADV_PURGEABLE_DONTNEED;
272}
273
274void xe_bo_set_purgeable_state(struct xe_bo *bo, enum xe_madv_purgeable_state new_state);
275
218static inline void xe_bo_unpin_map_no_vm(struct xe_bo *bo)276static inline void xe_bo_unpin_map_no_vm(struct xe_bo *bo)
219{277{
220 if (likely(bo)) {278 if (likely(bo)) {
drivers/gpu/drm/xe/xe_bo_types.h+6−0
@@ -108,6 +108,12 @@ struct xe_bo { · 107 unmodified lines
108 * from default108 * from default
109 */109 */
110 u64 min_align;110 u64 min_align;
111
112 /**
113 * @madv_purgeable: user space advise on BO purgeability, protected
114 * by BO's dma-resv lock.
115 */
116 u32 madv_purgeable;
111};117};
112 118
113#endif119#endif
drivers/gpu/drm/xe/xe_device.c+0−3
@@ -390,9 +390,6 @@ bool xe_is_xe_file(const struct file *file) · 389 unmodified lines
390}390}
391 391
392static struct drm_driver driver = {392static struct drm_driver driver = {
393 /* Don't use MTRRs here; the Xserver or userspace app should
394 * deal with them for Intel hardware.
395 */
396 .driver_features =393 .driver_features =
397 DRIVER_GEM |394 DRIVER_GEM |
398 DRIVER_RENDER | DRIVER_SYNCOBJ |395 DRIVER_RENDER | DRIVER_SYNCOBJ |
drivers/gpu/drm/xe/xe_dma_buf.c+24−0
@@ -223,6 +223,26 @@ struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags) · 222 unmodified lines
223 if (bo->vm)223 if (bo->vm)
224 return ERR_PTR(-EPERM);224 return ERR_PTR(-EPERM);
225 225
226 /*
227 * Reject exporting purgeable BOs. DONTNEED BOs can be purged
228 * at any time, making the exported dma-buf unusable. Purged BOs
229 * have no backing store and are permanently invalid.
230 */
231 ret = xe_bo_lock(bo, true);
232 if (ret)
233 return ERR_PTR(ret);
234
235 if (xe_bo_madv_is_dontneed(bo)) {
236 ret = -EBUSY;
237 goto out_unlock;
238 }
239
240 if (xe_bo_is_purged(bo)) {
241 ret = -EINVAL;
242 goto out_unlock;
243 }
244 xe_bo_unlock(bo);
245
226 ret = ttm_bo_setup_export(&bo->ttm, &ctx);246 ret = ttm_bo_setup_export(&bo->ttm, &ctx);
227 if (ret)247 if (ret)
228 return ERR_PTR(ret);248 return ERR_PTR(ret);
@@ -232,6 +252,10 @@ struct dma_buf *xe_gem_prime_export(struct drm_gem_object *obj, int flags) · 3 unmodified lines
232 buf->ops = &xe_dmabuf_ops;252 buf->ops = &xe_dmabuf_ops;
233 253
234 return buf;254 return buf;
255
256out_unlock:
257 xe_bo_unlock(bo);
258 return ERR_PTR(ret);
235}259}
236 260
237static struct drm_gem_object *261static struct drm_gem_object *
drivers/gpu/drm/xe/xe_ggtt.c+2−7
@@ -481,15 +481,10 @@ static void ggtt_node_remove(struct xe_ggtt_node *node) · 480 unmodified lines
481 xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node));481 xe_ggtt_clear(ggtt, xe_ggtt_node_addr(node), xe_ggtt_node_size(node));
482 drm_mm_remove_node(&node->base);482 drm_mm_remove_node(&node->base);
483 node->base.size = 0;483 node->base.size = 0;
484 mutex_unlock(&ggtt->lock);484 if (bound && node->invalidate_on_remove)
485
486 if (!bound)
487 goto free_node;
488
489 if (node->invalidate_on_remove)
490 xe_ggtt_invalidate(ggtt);485 xe_ggtt_invalidate(ggtt);
486 mutex_unlock(&ggtt->lock);
491 487
492free_node:
493 ggtt_node_fini(node);488 ggtt_node_fini(node);
494}489}
495 490
drivers/gpu/drm/xe/xe_gt_idle_types.h+3−3
@@ -3,8 +3,8 @@ · 2 unmodified lines
3 * Copyright © 2023 Intel Corporation3 * Copyright © 2023 Intel Corporation
4 */4 */
5 5
6#ifndef _XE_GT_IDLE_SYSFS_TYPES_H_6#ifndef _XE_GT_IDLE_TYPES_H_
7#define _XE_GT_IDLE_SYSFS_TYPES_H_7#define _XE_GT_IDLE_TYPES_H_
8 8
9#include <linux/spinlock.h>9#include <linux/spinlock.h>
10#include <linux/types.h>10#include <linux/types.h>
@@ -40,4 +40,4 @@ struct xe_gt_idle { · 29 unmodified lines
40 u64 (*idle_residency)(struct xe_guc_pc *pc);40 u64 (*idle_residency)(struct xe_guc_pc *pc);
41};41};
42 42
43#endif /* _XE_GT_IDLE_SYSFS_TYPES_H_ */43#endif /* _XE_GT_IDLE_TYPES_H_ */
drivers/gpu/drm/xe/xe_guc_exec_queue_types.h+2−2
@@ -3,8 +3,8 @@ · 2 unmodified lines
3 * Copyright © 2022 Intel Corporation3 * Copyright © 2022 Intel Corporation
4 */4 */
5 5
6#ifndef _XE_GUC_ENGINE_TYPES_H_6#ifndef _XE_GUC_EXEC_QUEUE_TYPES_H_
7#define _XE_GUC_ENGINE_TYPES_H_7#define _XE_GUC_EXEC_QUEUE_TYPES_H_
8 8
9#include <linux/spinlock.h>9#include <linux/spinlock.h>
10#include <linux/workqueue.h>10#include <linux/workqueue.h>
drivers/gpu/drm/xe/xe_heci_gsc.h+3−3
@@ -2,8 +2,8 @@ · 1 unmodified line
2/*2/*
3 * Copyright(c) 2023, Intel Corporation. All rights reserved.3 * Copyright(c) 2023, Intel Corporation. All rights reserved.
4 */4 */
5#ifndef __XE_HECI_GSC_DEV_H__5#ifndef _XE_HECI_GSC_H_
6#define __XE_HECI_GSC_DEV_H__6#define _XE_HECI_GSC_H_
7 7
8#include <linux/types.h>8#include <linux/types.h>
9 9
@@ -37,4 +37,4 @@ int xe_heci_gsc_init(struct xe_device *xe); · 27 unmodified lines
37void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir);37void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir);
38void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir);38void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir);
39 39
40#endif /* __XE_HECI_GSC_DEV_H__ */40#endif /* _XE_HECI_GSC_H_ */
drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.h+2−2
@@ -3,8 +3,8 @@ · 2 unmodified lines
3 * Copyright © 2023 Intel Corporation3 * Copyright © 2023 Intel Corporation
4 */4 */
5 5
6#ifndef _XE_ENGINE_CLASS_SYSFS_H_6#ifndef _XE_HW_ENGINE_CLASS_SYSFS_H_
7#define _XE_ENGINE_CLASS_SYSFS_H_7#define _XE_HW_ENGINE_CLASS_SYSFS_H_
8 8
9#include <linux/kobject.h>9#include <linux/kobject.h>
10 10
drivers/gpu/drm/xe/xe_late_bind_fw_types.h+2−2
@@ -3,8 +3,8 @@ · 2 unmodified lines
3 * Copyright © 2025 Intel Corporation3 * Copyright © 2025 Intel Corporation
4 */4 */
5 5
6#ifndef _XE_LATE_BIND_TYPES_H_6#ifndef _XE_LATE_BIND_FW_TYPES_H_
7#define _XE_LATE_BIND_TYPES_H_7#define _XE_LATE_BIND_FW_TYPES_H_
8 8
9#include <linux/iosys-map.h>9#include <linux/iosys-map.h>
10#include <linux/mutex.h>10#include <linux/mutex.h>
drivers/gpu/drm/xe/xe_pagefault.c+14−1
@@ -59,6 +59,19 @@ static int xe_pagefault_begin(struct drm_exec *exec, struct xe_vma *vma, · 58 unmodified lines
59 if (!bo)59 if (!bo)
60 return 0;60 return 0;
61 61
62 /*
63 * Skip validate/migrate for DONTNEED/purged BOs - repopulating
64 * their pages would prevent the shrinker from reclaiming them.
65 * For non-scratch VMs there is no safe fallback so fail the fault.
66 * For scratch VMs let xe_vma_rebind() run normally; it will install
67 * scratch PTEs so the GPU gets safe zero reads instead of faulting.
68 */
69 if (unlikely(xe_bo_madv_is_dontneed(bo) || xe_bo_is_purged(bo))) {
70 if (!xe_vm_has_scratch(vm))
71 return -EACCES;
72 return 0;
73 }
74
62 return need_vram_move ? xe_bo_migrate(bo, vram->placement, NULL, exec) :75 return need_vram_move ? xe_bo_migrate(bo, vram->placement, NULL, exec) :
63 xe_bo_validate(bo, vm, true, exec);76 xe_bo_validate(bo, vm, true, exec);
64}77}
@@ -145,7 +158,7 @@ static struct xe_vm *xe_pagefault_asid_to_vm(struct xe_device *xe, u32 asid) · 80 unmodified lines
145 158
146 down_read(&xe->usm.lock);159 down_read(&xe->usm.lock);
147 vm = xa_load(&xe->usm.asid_to_vm, asid);160 vm = xa_load(&xe->usm.asid_to_vm, asid);
148 if (vm && xe_vm_in_fault_mode(vm))161 if (vm && (xe_vm_in_fault_mode(vm) || xe_vm_has_scratch(vm)))
149 xe_vm_get(vm);162 xe_vm_get(vm);
150 else163 else
151 vm = ERR_PTR(-EINVAL);164 vm = ERR_PTR(-EINVAL);
drivers/gpu/drm/xe/xe_platform_types.h+2−2
@@ -3,8 +3,8 @@ · 2 unmodified lines
3 * Copyright © 2022 Intel Corporation3 * Copyright © 2022 Intel Corporation
4 */4 */
5 5
6#ifndef _XE_PLATFORM_INFO_TYPES_H_6#ifndef _XE_PLATFORM_TYPES_H_
7#define _XE_PLATFORM_INFO_TYPES_H_7#define _XE_PLATFORM_TYPES_H_
8 8
9/*9/*
10 * Keep this in graphics version based order and chronological order within a10 * Keep this in graphics version based order and chronological order within a
drivers/gpu/drm/xe/xe_pt.c+33−7
@@ -531,20 +531,26 @@ xe_pt_stage_bind_entry(struct xe_ptw *parent, pgoff_t offset, · 530 unmodified lines
531 /* Is this a leaf entry ?*/531 /* Is this a leaf entry ?*/
532 if (level == 0 || xe_pt_hugepte_possible(addr, next, level, xe_walk)) {532 if (level == 0 || xe_pt_hugepte_possible(addr, next, level, xe_walk)) {
533 struct xe_res_cursor *curs = xe_walk->curs;533 struct xe_res_cursor *curs = xe_walk->curs;
534 bool is_null = xe_vma_is_null(xe_walk->vma);534 struct xe_bo *bo = xe_vma_bo(xe_walk->vma);
535 bool is_vram = is_null ? false : xe_res_is_vram(curs);535 bool is_null_or_purged = xe_vma_is_null(xe_walk->vma) ||
536 (bo && xe_bo_is_purged(bo));
537 bool is_vram = is_null_or_purged ? false : xe_res_is_vram(curs);
536 538
537 XE_WARN_ON(xe_walk->va_curs_start != addr);539 XE_WARN_ON(xe_walk->va_curs_start != addr);
538 540
539 if (xe_walk->clear_pt) {541 if (xe_walk->clear_pt) {
540 pte = 0;542 pte = 0;
541 } else {543 } else {
542 pte = vm->pt_ops->pte_encode_vma(is_null ? 0 :544 /*
545 * For purged BOs, treat like null VMAs - pass address 0.
546 * The pte_encode_vma will set XE_PTE_NULL flag for scratch mapping.
547 */
548 pte = vm->pt_ops->pte_encode_vma(is_null_or_purged ? 0 :
543 xe_res_dma(curs) +549 xe_res_dma(curs) +
544 xe_walk->dma_offset,550 xe_walk->dma_offset,
545 xe_walk->vma,551 xe_walk->vma,
546 pat_index, level);552 pat_index, level);
547 if (!is_null)553 if (!is_null_or_purged)
548 pte |= is_vram ? xe_walk->default_vram_pte :554 pte |= is_vram ? xe_walk->default_vram_pte :
549 xe_walk->default_system_pte;555 xe_walk->default_system_pte;
550 556
@@ -568,7 +574,7 @@ xe_pt_stage_bind_entry(struct xe_ptw *parent, pgoff_t offset, · 17 unmodified lines
568 if (unlikely(ret))574 if (unlikely(ret))
569 return ret;575 return ret;
570 576
571 if (!is_null && !xe_walk->clear_pt)577 if (!is_null_or_purged && !xe_walk->clear_pt)
572 xe_res_next(curs, next - addr);578 xe_res_next(curs, next - addr);
573 xe_walk->va_curs_start = next;579 xe_walk->va_curs_start = next;
574 xe_walk->vma->gpuva.flags |= (XE_VMA_PTE_4K << level);580 xe_walk->vma->gpuva.flags |= (XE_VMA_PTE_4K << level);
@@ -721,6 +727,26 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, · 146 unmodified lines
721 };727 };
722 struct xe_pt *pt = vm->pt_root[tile->id];728 struct xe_pt *pt = vm->pt_root[tile->id];
723 int ret;729 int ret;
730 bool is_purged = false;
731
732 /*
733 * Check if BO is purged:
734 * - Scratch VMs: Use scratch PTEs (XE_PTE_NULL) for safe zero reads
735 * - Non-scratch VMs: Clear PTEs to zero (non-present) to avoid mapping to phys addr 0
736 *
737 * For non-scratch VMs, we force clear_pt=true so leaf PTEs become completely
738 * zero instead of creating a PRESENT mapping to physical address 0.
739 */
740 if (bo && xe_bo_is_purged(bo)) {
741 is_purged = true;
742
743 /*
744 * For non-scratch VMs, a NULL rebind should use zero PTEs
745 * (non-present), not a present PTE to phys 0.
746 */
747 if (!xe_vm_has_scratch(vm))
748 xe_walk.clear_pt = true;
749 }
724 750
725 if (range) {751 if (range) {
726 /* Move this entire thing to xe_svm.c? */752 /* Move this entire thing to xe_svm.c? */
@@ -756,11 +782,11 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, · 29 unmodified lines
756 }782 }
757 783
758 xe_walk.default_vram_pte |= XE_PPGTT_PTE_DM;784 xe_walk.default_vram_pte |= XE_PPGTT_PTE_DM;
759 xe_walk.dma_offset = bo ? vram_region_gpu_offset(bo->ttm.resource) : 0;785 xe_walk.dma_offset = (bo && !is_purged) ? vram_region_gpu_offset(bo->ttm.resource) : 0;
760 if (!range)786 if (!range)
761 xe_bo_assert_held(bo);787 xe_bo_assert_held(bo);
762 788
763 if (!xe_vma_is_null(vma) && !range) {789 if (!xe_vma_is_null(vma) && !range && !is_purged) {
764 if (xe_vma_is_userptr(vma))790 if (xe_vma_is_userptr(vma))
765 xe_res_first_dma(to_userptr_vma(vma)->userptr.pages.dma_addr, 0,791 xe_res_first_dma(to_userptr_vma(vma)->userptr.pages.dma_addr, 0,
766 xe_vma_size(vma), &curs);792 xe_vma_size(vma), &curs);
drivers/gpu/drm/xe/xe_query.c+2−0
@@ -342,6 +342,8 @@ static int query_config(struct xe_device *xe, struct drm_xe_device_query *query) · 341 unmodified lines
342 DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY;342 DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY;
343 config->info[DRM_XE_QUERY_CONFIG_FLAGS] |=343 config->info[DRM_XE_QUERY_CONFIG_FLAGS] |=
344 DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX;344 DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX;
345 config->info[DRM_XE_QUERY_CONFIG_FLAGS] |=
346 DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT;
345 config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT] =347 config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT] =
346 xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;348 xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
347 config->info[DRM_XE_QUERY_CONFIG_VA_BITS] = xe->info.va_bits;349 config->info[DRM_XE_QUERY_CONFIG_VA_BITS] = xe->info.va_bits;
drivers/gpu/drm/xe/xe_svm.c+1−0
@@ -322,6 +322,7 @@ static void xe_vma_set_default_attributes(struct xe_vma *vma) · 321 unmodified lines
322 .preferred_loc.migration_policy = DRM_XE_MIGRATE_ALL_PAGES,322 .preferred_loc.migration_policy = DRM_XE_MIGRATE_ALL_PAGES,
323 .pat_index = vma->attr.default_pat_index,323 .pat_index = vma->attr.default_pat_index,
324 .atomic_access = DRM_XE_ATOMIC_UNDEFINED,324 .atomic_access = DRM_XE_ATOMIC_UNDEFINED,
325 .purgeable_state = XE_MADV_PURGEABLE_WILLNEED,
325 };326 };
326 327
327 xe_vma_mem_attr_copy(&vma->attr, &default_attr);328 xe_vma_mem_attr_copy(&vma->attr, &default_attr);
drivers/gpu/drm/xe/xe_tile_printk.h+2−2
@@ -3,8 +3,8 @@ · 2 unmodified lines
3 * Copyright © 2025 Intel Corporation3 * Copyright © 2025 Intel Corporation
4 */4 */
5 5
6#ifndef _xe_tile_printk_H_6#ifndef _XE_TILE_PRINTK_H_
7#define _xe_tile_printk_H_7#define _XE_TILE_PRINTK_H_
8 8
9#include "xe_printk.h"9#include "xe_printk.h"
10 10
drivers/gpu/drm/xe/xe_vm.c+95−17
@@ -40,6 +40,7 @@ · 39 unmodified lines
40#include "xe_tile.h"40#include "xe_tile.h"
41#include "xe_tlb_inval.h"41#include "xe_tlb_inval.h"
42#include "xe_trace_bo.h"42#include "xe_trace_bo.h"
43#include "xe_vm_madvise.h"
43#include "xe_wa.h"44#include "xe_wa.h"
44 45
45static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)46static struct drm_gem_object *xe_vm_obj(struct xe_vm *vm)
@@ -327,6 +328,7 @@ void xe_vm_kill(struct xe_vm *vm, bool unlocked) · 281 unmodified lines
327static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)328static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
328{329{
329 struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm);330 struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm);
331 struct xe_bo *bo = gem_to_xe_bo(vm_bo->obj);
330 struct drm_gpuva *gpuva;332 struct drm_gpuva *gpuva;
331 int ret;333 int ret;
332 334
@@ -335,10 +337,16 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec) · 2 unmodified lines
335 list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,337 list_move_tail(&gpuva_to_vma(gpuva)->combined_links.rebind,
336 &vm->rebind_list);338 &vm->rebind_list);
337 339
340 /* Skip re-populating purged BOs, rebind maps scratch pages. */
341 if (xe_bo_is_purged(bo)) {
342 vm_bo->evicted = false;
343 return 0;
344 }
345
338 if (!try_wait_for_completion(&vm->xe->pm_block))346 if (!try_wait_for_completion(&vm->xe->pm_block))
339 return -EAGAIN;347 return -EAGAIN;
340 348
341 ret = xe_bo_validate(gem_to_xe_bo(vm_bo->obj), vm, false, exec);349 ret = xe_bo_validate(bo, vm, false, exec);
342 if (ret)350 if (ret)
343 return ret;351 return ret;
344 352
@@ -1147,6 +1155,7 @@ static struct xe_vma *xe_vma_create(struct xe_vm *vm, · 802 unmodified lines
1147static void xe_vma_destroy_late(struct xe_vma *vma)1155static void xe_vma_destroy_late(struct xe_vma *vma)
1148{1156{
1149 struct xe_vm *vm = xe_vma_vm(vma);1157 struct xe_vm *vm = xe_vma_vm(vma);
1158 struct xe_bo *bo = xe_vma_bo(vma);
1150 1159
1151 if (vma->ufence) {1160 if (vma->ufence) {
1152 xe_sync_ufence_put(vma->ufence);1161 xe_sync_ufence_put(vma->ufence);
@@ -1161,7 +1170,7 @@ static void xe_vma_destroy_late(struct xe_vma *vma) · 8 unmodified lines
1161 } else if (xe_vma_is_null(vma) || xe_vma_is_cpu_addr_mirror(vma)) {1170 } else if (xe_vma_is_null(vma) || xe_vma_is_cpu_addr_mirror(vma)) {
1162 xe_vm_put(vm);1171 xe_vm_put(vm);
1163 } else {1172 } else {
1164 xe_bo_put(xe_vma_bo(vma));1173 xe_bo_put(bo);
1165 }1174 }
1166 1175
1167 xe_vma_free(vma);1176 xe_vma_free(vma);
@@ -1187,6 +1196,7 @@ static void vma_destroy_cb(struct dma_fence *fence, · 19 unmodified lines
1187static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)1196static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
1188{1197{
1189 struct xe_vm *vm = xe_vma_vm(vma);1198 struct xe_vm *vm = xe_vma_vm(vma);
1199 struct xe_bo *bo = xe_vma_bo(vma);
1190 1200
1191 lockdep_assert_held_write(&vm->lock);1201 lockdep_assert_held_write(&vm->lock);
1192 xe_assert(vm->xe, list_empty(&vma->combined_links.destroy));1202 xe_assert(vm->xe, list_empty(&vma->combined_links.destroy));
@@ -1195,9 +1205,10 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence) · 2 unmodified lines
1195 xe_assert(vm->xe, vma->gpuva.flags & XE_VMA_DESTROYED);1205 xe_assert(vm->xe, vma->gpuva.flags & XE_VMA_DESTROYED);
1196 xe_userptr_destroy(to_userptr_vma(vma));1206 xe_userptr_destroy(to_userptr_vma(vma));
1197 } else if (!xe_vma_is_null(vma) && !xe_vma_is_cpu_addr_mirror(vma)) {1207 } else if (!xe_vma_is_null(vma) && !xe_vma_is_cpu_addr_mirror(vma)) {
1198 xe_bo_assert_held(xe_vma_bo(vma));1208 xe_bo_assert_held(bo);
1199 1209
1200 drm_gpuva_unlink(&vma->gpuva);1210 drm_gpuva_unlink(&vma->gpuva);
1211 xe_bo_recompute_purgeable_state(bo);
1201 }1212 }
1202 1213
1203 xe_vm_assert_held(vm);1214 xe_vm_assert_held(vm);
@@ -1427,6 +1438,9 @@ static u64 xelp_pte_encode_bo(struct xe_bo *bo, u64 bo_offset, · 223 unmodified lines
1427static u64 xelp_pte_encode_vma(u64 pte, struct xe_vma *vma,1438static u64 xelp_pte_encode_vma(u64 pte, struct xe_vma *vma,
1428 u16 pat_index, u32 pt_level)1439 u16 pat_index, u32 pt_level)
1429{1440{
1441 struct xe_bo *bo = xe_vma_bo(vma);
1442 struct xe_vm *vm = xe_vma_vm(vma);
1443
1430 pte |= XE_PAGE_PRESENT;1444 pte |= XE_PAGE_PRESENT;
1431 1445
1432 if (likely(!xe_vma_read_only(vma)))1446 if (likely(!xe_vma_read_only(vma)))
@@ -1435,7 +1449,13 @@ static u64 xelp_pte_encode_vma(u64 pte, struct xe_vma *vma, · 2 unmodified lines
1435 pte |= pte_encode_pat_index(pat_index, pt_level);1449 pte |= pte_encode_pat_index(pat_index, pt_level);
1436 pte |= pte_encode_ps(pt_level);1450 pte |= pte_encode_ps(pt_level);
1437 1451
1438 if (unlikely(xe_vma_is_null(vma)))1452 /*
1453 * NULL PTEs redirect to scratch page (return zeros on read).
1454 * Set for: 1) explicit null VMAs, 2) purged BOs on scratch VMs.
1455 * Never set NULL flag without scratch page - causes undefined behavior.
1456 */
1457 if (unlikely(xe_vma_is_null(vma) ||
1458 (bo && xe_bo_is_purged(bo) && xe_vm_has_scratch(vm))))
1439 pte |= XE_PTE_NULL;1459 pte |= XE_PTE_NULL;
1440 1460
1441 return pte;1461 return pte;
@@ -2751,6 +2771,7 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops, · 1309 unmodified lines
2751 .atomic_access = DRM_XE_ATOMIC_UNDEFINED,2771 .atomic_access = DRM_XE_ATOMIC_UNDEFINED,
2752 .default_pat_index = op->map.pat_index,2772 .default_pat_index = op->map.pat_index,
2753 .pat_index = op->map.pat_index,2773 .pat_index = op->map.pat_index,
2774 .purgeable_state = XE_MADV_PURGEABLE_WILLNEED,
2754 };2775 };
2755 2776
2756 flags |= op->map.vma_flags & XE_VMA_CREATE_MASK;2777 flags |= op->map.vma_flags & XE_VMA_CREATE_MASK;
@@ -2990,8 +3011,22 @@ static void vm_bind_ioctl_ops_unwind(struct xe_vm *vm, · 233 unmodified lines
2990 }3011 }
2991}3012}
2992 3013
3014/**
3015 * struct xe_vma_lock_and_validate_flags - Flags for vma_lock_and_validate()
3016 * @res_evict: Allow evicting resources during validation
3017 * @validate: Perform BO validation
3018 * @request_decompress: Request BO decompression
3019 * @check_purged: Reject operation if BO is purged
3020 */
3021struct xe_vma_lock_and_validate_flags {
3022 u32 res_evict : 1;
3023 u32 validate : 1;
3024 u32 request_decompress : 1;
3025 u32 check_purged : 1;
3026};
3027
2993static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,3028static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma,
2994 bool res_evict, bool validate, bool request_decompress)3029 struct xe_vma_lock_and_validate_flags flags)
2995{3030{
2996 struct xe_bo *bo = xe_vma_bo(vma);3031 struct xe_bo *bo = xe_vma_bo(vma);
2997 struct xe_vm *vm = xe_vma_vm(vma);3032 struct xe_vm *vm = xe_vma_vm(vma);
@@ -3000,15 +3035,24 @@ static int vma_lock_and_validate(struct drm_exec *exec, struct xe_vma *vma, · 2 unmodified lines
3000 if (bo) {3035 if (bo) {
3001 if (!bo->vm)3036 if (!bo->vm)
3002 err = drm_exec_lock_obj(exec, &bo->ttm.base);3037 err = drm_exec_lock_obj(exec, &bo->ttm.base);
3003 if (!err && validate)3038
3039 /* Reject new mappings to DONTNEED/purged BOs; allow cleanup operations */
3040 if (!err && flags.check_purged) {
3041 if (xe_bo_madv_is_dontneed(bo))
3042 err = -EBUSY; /* BO marked purgeable */
3043 else if (xe_bo_is_purged(bo))
3044 err = -EINVAL; /* BO already purged */
3045 }
3046
3047 if (!err && flags.validate)
3004 err = xe_bo_validate(bo, vm,3048 err = xe_bo_validate(bo, vm,
3005 xe_vm_allow_vm_eviction(vm) &&3049 xe_vm_allow_vm_eviction(vm) &&
3006 res_evict, exec);3050 flags.res_evict, exec);
3007 3051
3008 if (err)3052 if (err)
3009 return err;3053 return err;
3010 3054
3011 if (request_decompress)3055 if (flags.request_decompress)
3012 err = xe_bo_decompress(bo);3056 err = xe_bo_decompress(bo);
3013 }3057 }
3014 3058
@@ -3102,10 +3146,14 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm, · 87 unmodified lines
3102 case DRM_GPUVA_OP_MAP:3146 case DRM_GPUVA_OP_MAP:
3103 if (!op->map.invalidate_on_bind)3147 if (!op->map.invalidate_on_bind)
3104 err = vma_lock_and_validate(exec, op->map.vma,3148 err = vma_lock_and_validate(exec, op->map.vma,
3105 res_evict,3149 (struct xe_vma_lock_and_validate_flags) {
3106 !xe_vm_in_fault_mode(vm) ||3150 .res_evict = res_evict,
3107 op->map.immediate,3151 .validate = !xe_vm_in_fault_mode(vm) ||
3108 op->map.request_decompress);3152 op->map.immediate,
3153 .request_decompress =
3154 op->map.request_decompress,
3155 .check_purged = true,
3156 });
3109 break;3157 break;
3110 case DRM_GPUVA_OP_REMAP:3158 case DRM_GPUVA_OP_REMAP:
3111 err = check_ufence(gpuva_to_vma(op->base.remap.unmap->va));3159 err = check_ufence(gpuva_to_vma(op->base.remap.unmap->va));
@@ -3114,13 +3162,28 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm, · 2 unmodified lines
3114 3162
3115 err = vma_lock_and_validate(exec,3163 err = vma_lock_and_validate(exec,
3116 gpuva_to_vma(op->base.remap.unmap->va),3164 gpuva_to_vma(op->base.remap.unmap->va),
3117 res_evict, false, false);3165 (struct xe_vma_lock_and_validate_flags) {
3166 .res_evict = res_evict,
3167 .validate = false,
3168 .request_decompress = false,
3169 .check_purged = false,
3170 });
3118 if (!err && op->remap.prev)3171 if (!err && op->remap.prev)
3119 err = vma_lock_and_validate(exec, op->remap.prev,3172 err = vma_lock_and_validate(exec, op->remap.prev,
3120 res_evict, true, false);3173 (struct xe_vma_lock_and_validate_flags) {
3174 .res_evict = res_evict,
3175 .validate = true,
3176 .request_decompress = false,
3177 .check_purged = true,
3178 });
3121 if (!err && op->remap.next)3179 if (!err && op->remap.next)
3122 err = vma_lock_and_validate(exec, op->remap.next,3180 err = vma_lock_and_validate(exec, op->remap.next,
3123 res_evict, true, false);3181 (struct xe_vma_lock_and_validate_flags) {
3182 .res_evict = res_evict,
3183 .validate = true,
3184 .request_decompress = false,
3185 .check_purged = true,
3186 });
3124 break;3187 break;
3125 case DRM_GPUVA_OP_UNMAP:3188 case DRM_GPUVA_OP_UNMAP:
3126 err = check_ufence(gpuva_to_vma(op->base.unmap.va));3189 err = check_ufence(gpuva_to_vma(op->base.unmap.va));
@@ -3129,7 +3192,12 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm, · 2 unmodified lines
3129 3192
3130 err = vma_lock_and_validate(exec,3193 err = vma_lock_and_validate(exec,
3131 gpuva_to_vma(op->base.unmap.va),3194 gpuva_to_vma(op->base.unmap.va),
3132 res_evict, false, false);3195 (struct xe_vma_lock_and_validate_flags) {
3196 .res_evict = res_evict,
3197 .validate = false,
3198 .request_decompress = false,
3199 .check_purged = false,
3200 });
3133 break;3201 break;
3134 case DRM_GPUVA_OP_PREFETCH:3202 case DRM_GPUVA_OP_PREFETCH:
3135 {3203 {
@@ -3142,9 +3210,19 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm, · 6 unmodified lines
3142 region <= ARRAY_SIZE(region_to_mem_type));3210 region <= ARRAY_SIZE(region_to_mem_type));
3143 }3211 }
3144 3212
3213 /*
3214 * Prefetch attempts to migrate BO's backing store without
3215 * repopulating it first. Purged BOs have no backing store
3216 * to migrate, so reject the operation.
3217 */
3145 err = vma_lock_and_validate(exec,3218 err = vma_lock_and_validate(exec,
3146 gpuva_to_vma(op->base.prefetch.va),3219 gpuva_to_vma(op->base.prefetch.va),
3147 res_evict, false, false);3220 (struct xe_vma_lock_and_validate_flags) {
3221 .res_evict = res_evict,
3222 .validate = false,
3223 .request_decompress = false,
3224 .check_purged = true,
3225 });
3148 if (!err && !xe_vma_has_no_bo(vma))3226 if (!err && !xe_vma_has_no_bo(vma))
3149 err = xe_bo_migrate(xe_vma_bo(vma),3227 err = xe_bo_migrate(xe_vma_bo(vma),
3150 region_to_mem_type[region],3228 region_to_mem_type[region],
drivers/gpu/drm/xe/xe_vm_madvise.c+299−4
@@ -13,6 +13,7 @@ · 12 unmodified lines
13#include "xe_pt.h"13#include "xe_pt.h"
14#include "xe_svm.h"14#include "xe_svm.h"
15#include "xe_tlb_inval.h"15#include "xe_tlb_inval.h"
16#include "xe_vm.h"
16 17
17struct xe_vmas_in_madvise_range {18struct xe_vmas_in_madvise_range {
18 u64 addr;19 u64 addr;
@@ -26,6 +27,8 @@ struct xe_vmas_in_madvise_range { · 7 unmodified lines
26/**27/**
27 * struct xe_madvise_details - Argument to madvise_funcs28 * struct xe_madvise_details - Argument to madvise_funcs
28 * @dpagemap: Reference-counted pointer to a struct drm_pagemap.29 * @dpagemap: Reference-counted pointer to a struct drm_pagemap.
30 * @has_purged_bo: Track if any BO was purged (for purgeable state)
31 * @retained_ptr: User pointer for retained value (for purgeable state)
29 *32 *
30 * The madvise IOCTL handler may, in addition to the user-space33 * The madvise IOCTL handler may, in addition to the user-space
31 * args, have additional info to pass into the madvise_func that34 * args, have additional info to pass into the madvise_func that
@@ -34,6 +37,8 @@ struct xe_vmas_in_madvise_range { · 2 unmodified lines
34 */37 */
35struct xe_madvise_details {38struct xe_madvise_details {
36 struct drm_pagemap *dpagemap;39 struct drm_pagemap *dpagemap;
40 bool has_purged_bo;
41 u64 retained_ptr;
37};42};
38 43
39static int get_vmas(struct xe_vm *vm, struct xe_vmas_in_madvise_range *madvise_range)44static int get_vmas(struct xe_vm *vm, struct xe_vmas_in_madvise_range *madvise_range)
@@ -180,6 +185,222 @@ static void madvise_pat_index(struct xe_device *xe, struct xe_vm *vm, · 140 unmodified lines
180 }185 }
181}186}
182 187
188/**
189 * xe_bo_is_dmabuf_shared() - Check if BO is shared via dma-buf
190 * @bo: Buffer object
191 *
192 * Prevent marking imported or exported dma-bufs as purgeable.
193 * For imported BOs, Xe doesn't own the backing store and cannot
194 * safely reclaim pages (exporter or other devices may still be
195 * using them). For exported BOs, external devices may have active
196 * mappings we cannot track.
197 *
198 * Return: true if BO is imported or exported, false otherwise
199 */
200static bool xe_bo_is_dmabuf_shared(struct xe_bo *bo)
201{
202 struct drm_gem_object *obj = &bo->ttm.base;
203
204 /* Imported: exporter owns backing store */
205 if (drm_gem_is_imported(obj))
206 return true;
207
208 /* Exported: external devices may be accessing */
209 if (obj->dma_buf)
210 return true;
211
212 return false;
213}
214
215/**
216 * enum xe_bo_vmas_purge_state - VMA purgeable state aggregation
217 *
218 * Distinguishes whether a BO's VMAs are all DONTNEED, have at least
219 * one WILLNEED, or have no VMAs at all.
220 *
221 * Enum values align with XE_MADV_PURGEABLE_* states for consistency.
222 */
223enum xe_bo_vmas_purge_state {
224 /** @XE_BO_VMAS_STATE_WILLNEED: At least one VMA is WILLNEED */
225 XE_BO_VMAS_STATE_WILLNEED = 0,
226 /** @XE_BO_VMAS_STATE_DONTNEED: All VMAs are DONTNEED */
227 XE_BO_VMAS_STATE_DONTNEED = 1,
228 /** @XE_BO_VMAS_STATE_NO_VMAS: BO has no VMAs */
229 XE_BO_VMAS_STATE_NO_VMAS = 2,
230};
231
232/*
233 * xe_bo_recompute_purgeable_state() casts between xe_bo_vmas_purge_state and
234 * xe_madv_purgeable_state. Enforce that WILLNEED=0 and DONTNEED=1 match across
235 * both enums so the single-line cast is always valid.
236 */
237static_assert(XE_BO_VMAS_STATE_WILLNEED == (int)XE_MADV_PURGEABLE_WILLNEED,
238 "VMA purge state WILLNEED must equal madv purgeable WILLNEED");
239static_assert(XE_BO_VMAS_STATE_DONTNEED == (int)XE_MADV_PURGEABLE_DONTNEED,
240 "VMA purge state DONTNEED must equal madv purgeable DONTNEED");
241
242/**
243 * xe_bo_all_vmas_dontneed() - Determine BO VMA purgeable state
244 * @bo: Buffer object
245 *
246 * Check all VMAs across all VMs to determine aggregate purgeable state.
247 * Shared BOs require unanimous DONTNEED state from all mappings.
248 *
249 * Caller must hold BO dma-resv lock.
250 *
251 * Return: XE_BO_VMAS_STATE_DONTNEED if all VMAs are DONTNEED,
252 * XE_BO_VMAS_STATE_WILLNEED if at least one VMA is not DONTNEED,
253 * XE_BO_VMAS_STATE_NO_VMAS if BO has no VMAs
254 */
255static enum xe_bo_vmas_purge_state xe_bo_all_vmas_dontneed(struct xe_bo *bo)
256{
257 struct drm_gpuvm_bo *vm_bo;
258 struct drm_gpuva *gpuva;
259 struct drm_gem_object *obj = &bo->ttm.base;
260 bool has_vmas = false;
261
262 xe_bo_assert_held(bo);
263
264 /* Shared dma-bufs cannot be purgeable */
265 if (xe_bo_is_dmabuf_shared(bo))
266 return XE_BO_VMAS_STATE_WILLNEED;
267
268 drm_gem_for_each_gpuvm_bo(vm_bo, obj) {
269 drm_gpuvm_bo_for_each_va(gpuva, vm_bo) {
270 struct xe_vma *vma = gpuva_to_vma(gpuva);
271
272 has_vmas = true;
273
274 /* Any non-DONTNEED VMA prevents purging */
275 if (vma->attr.purgeable_state != XE_MADV_PURGEABLE_DONTNEED)
276 return XE_BO_VMAS_STATE_WILLNEED;
277 }
278 }
279
280 /*
281 * No VMAs => preserve existing BO purgeable state.
282 * Avoids incorrectly flipping DONTNEED -> WILLNEED when last VMA unmapped.
283 */
284 if (!has_vmas)
285 return XE_BO_VMAS_STATE_NO_VMAS;
286
287 return XE_BO_VMAS_STATE_DONTNEED;
288}
289
290/**
291 * xe_bo_recompute_purgeable_state() - Recompute BO purgeable state from VMAs
292 * @bo: Buffer object
293 *
294 * Walk all VMAs to determine if BO should be purgeable or not.
295 * Shared BOs require unanimous DONTNEED state from all mappings.
296 * If the BO has no VMAs the existing state is preserved.
297 *
298 * Locking: Caller must hold BO dma-resv lock. When iterating GPUVM lists,
299 * VM lock must also be held (write) to prevent concurrent VMA modifications.
300 * This is satisfied at both call sites:
301 * - xe_vma_destroy(): holds vm->lock write
302 * - madvise_purgeable(): holds vm->lock write (from madvise ioctl path)
303 *
304 * Return: nothing
305 */
306void xe_bo_recompute_purgeable_state(struct xe_bo *bo)
307{
308 enum xe_bo_vmas_purge_state vma_state;
309
310 if (!bo)
311 return;
312
313 xe_bo_assert_held(bo);
314
315 /*
316 * Once purged, always purged. Cannot transition back to WILLNEED.
317 * This matches i915 semantics where purged BOs are permanently invalid.
318 */
319 if (bo->madv_purgeable == XE_MADV_PURGEABLE_PURGED)
320 return;
321
322 vma_state = xe_bo_all_vmas_dontneed(bo);
323
324 if (vma_state != (enum xe_bo_vmas_purge_state)bo->madv_purgeable &&
325 vma_state != XE_BO_VMAS_STATE_NO_VMAS)
326 xe_bo_set_purgeable_state(bo, (enum xe_madv_purgeable_state)vma_state);
327}
328
329/**
330 * madvise_purgeable - Handle purgeable buffer object advice
331 * @xe: XE device
332 * @vm: VM
333 * @vmas: Array of VMAs
334 * @num_vmas: Number of VMAs
335 * @op: Madvise operation
336 * @details: Madvise details for return values
337 *
338 * Handles DONTNEED/WILLNEED/PURGED states. Tracks if any BO was purged
339 * in details->has_purged_bo for later copy to userspace.
340 */
341static void madvise_purgeable(struct xe_device *xe, struct xe_vm *vm,
342 struct xe_vma **vmas, int num_vmas,
343 struct drm_xe_madvise *op,
344 struct xe_madvise_details *details)
345{
346 int i;
347
348 xe_assert(vm->xe, op->type == DRM_XE_VMA_ATTR_PURGEABLE_STATE);
349
350 for (i = 0; i < num_vmas; i++) {
351 struct xe_bo *bo = xe_vma_bo(vmas[i]);
352
353 if (!bo) {
354 /* Purgeable state applies to BOs only, skip non-BO VMAs */
355 vmas[i]->skip_invalidation = true;
356 continue;
357 }
358
359 /* BO must be locked before modifying madv state */
360 xe_bo_assert_held(bo);
361
362 /* Skip shared dma-bufs - no PTEs to zap */
363 if (xe_bo_is_dmabuf_shared(bo)) {
364 vmas[i]->skip_invalidation = true;
365 continue;
366 }
367
368 /*
369 * Once purged, always purged. Cannot transition back to WILLNEED.
370 * This matches i915 semantics where purged BOs are permanently invalid.
371 */
372 if (xe_bo_is_purged(bo)) {
373 details->has_purged_bo = true;
374 vmas[i]->skip_invalidation = true;
375 continue;
376 }
377
378 switch (op->purge_state_val.val) {
379 case DRM_XE_VMA_PURGEABLE_STATE_WILLNEED:
380 vmas[i]->attr.purgeable_state = XE_MADV_PURGEABLE_WILLNEED;
381 vmas[i]->skip_invalidation = true;
382
383 xe_bo_recompute_purgeable_state(bo);
384 break;
385 case DRM_XE_VMA_PURGEABLE_STATE_DONTNEED:
386 vmas[i]->attr.purgeable_state = XE_MADV_PURGEABLE_DONTNEED;
387 /*
388 * Don't zap PTEs at DONTNEED time -- pages are still
389 * alive. The zap happens in xe_bo_move_notify() right
390 * before the shrinker frees them.
391 */
392 vmas[i]->skip_invalidation = true;
393
394 xe_bo_recompute_purgeable_state(bo);
395 break;
396 default:
397 /* Should never hit - values validated in madvise_args_are_sane() */
398 xe_assert(vm->xe, 0);
399 return;
400 }
401 }
402}
403
183typedef void (*madvise_func)(struct xe_device *xe, struct xe_vm *vm,404typedef void (*madvise_func)(struct xe_device *xe, struct xe_vm *vm,
184 struct xe_vma **vmas, int num_vmas,405 struct xe_vma **vmas, int num_vmas,
185 struct drm_xe_madvise *op,406 struct drm_xe_madvise *op,
@@ -189,6 +410,7 @@ static const madvise_func madvise_funcs[] = { · 3 unmodified lines
189 [DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC] = madvise_preferred_mem_loc,410 [DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC] = madvise_preferred_mem_loc,
190 [DRM_XE_MEM_RANGE_ATTR_ATOMIC] = madvise_atomic,411 [DRM_XE_MEM_RANGE_ATTR_ATOMIC] = madvise_atomic,
191 [DRM_XE_MEM_RANGE_ATTR_PAT] = madvise_pat_index,412 [DRM_XE_MEM_RANGE_ATTR_PAT] = madvise_pat_index,
413 [DRM_XE_VMA_ATTR_PURGEABLE_STATE] = madvise_purgeable,
192};414};
193 415
194static u8 xe_zap_ptes_in_madvise_range(struct xe_vm *vm, u64 start, u64 end)416static u8 xe_zap_ptes_in_madvise_range(struct xe_vm *vm, u64 start, u64 end)
@@ -319,6 +541,19 @@ static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madv · 124 unmodified lines
319 return false;541 return false;
320 break;542 break;
321 }543 }
544 case DRM_XE_VMA_ATTR_PURGEABLE_STATE:
545 {
546 u32 val = args->purge_state_val.val;
547
548 if (XE_IOCTL_DBG(xe, !(val == DRM_XE_VMA_PURGEABLE_STATE_WILLNEED ||
549 val == DRM_XE_VMA_PURGEABLE_STATE_DONTNEED)))
550 return false;
551
552 if (XE_IOCTL_DBG(xe, args->purge_state_val.pad))
553 return false;
554
555 break;
556 }
322 default:557 default:
323 if (XE_IOCTL_DBG(xe, 1))558 if (XE_IOCTL_DBG(xe, 1))
324 return false;559 return false;
@@ -337,6 +572,12 @@ static int xe_madvise_details_init(struct xe_vm *vm, const struct drm_xe_madvise · 12 unmodified lines
337 572
338 memset(details, 0, sizeof(*details));573 memset(details, 0, sizeof(*details));
339 574
575 /* Store retained pointer for purgeable state */
576 if (args->type == DRM_XE_VMA_ATTR_PURGEABLE_STATE) {
577 details->retained_ptr = args->purge_state_val.retained_ptr;
578 return 0;
579 }
580
340 if (args->type == DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC) {581 if (args->type == DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC) {
341 int fd = args->preferred_mem_loc.devmem_fd;582 int fd = args->preferred_mem_loc.devmem_fd;
342 struct drm_pagemap *dpagemap;583 struct drm_pagemap *dpagemap;
@@ -365,6 +606,21 @@ static void xe_madvise_details_fini(struct xe_madvise_details *details) · 22 unmodified lines
365 drm_pagemap_put(details->dpagemap);606 drm_pagemap_put(details->dpagemap);
366}607}
367 608
609static int xe_madvise_purgeable_retained_to_user(const struct xe_madvise_details *details)
610{
611 u32 retained;
612
613 if (!details->retained_ptr)
614 return 0;
615
616 retained = !details->has_purged_bo;
617
618 if (put_user(retained, (u32 __user *)u64_to_user_ptr(details->retained_ptr)))
619 return -EFAULT;
620
621 return 0;
622}
623
368static bool check_bo_args_are_sane(struct xe_vm *vm, struct xe_vma **vmas,624static bool check_bo_args_are_sane(struct xe_vm *vm, struct xe_vma **vmas,
369 int num_vmas, u32 atomic_val)625 int num_vmas, u32 atomic_val)
370{626{
@@ -416,13 +672,21 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil · 45 unmodified lines
416 struct xe_device *xe = to_xe_device(dev);672 struct xe_device *xe = to_xe_device(dev);
417 struct xe_file *xef = to_xe_file(file);673 struct xe_file *xef = to_xe_file(file);
418 struct drm_xe_madvise *args = data;674 struct drm_xe_madvise *args = data;
419 struct xe_vmas_in_madvise_range madvise_range = {.addr = args->start,675 struct xe_vmas_in_madvise_range madvise_range = {
420 .range = args->range, };676 /*
677 * Userspace may pass canonical (sign-extended) addresses.
678 * Strip the sign extension to get the internal non-canonical
679 * form used by the GPUVM, matching xe_vm_bind_ioctl() behavior.
680 */
681 .addr = xe_device_uncanonicalize_addr(xe, args->start),
682 .range = args->range,
683 };
421 struct xe_madvise_details details;684 struct xe_madvise_details details;
422 u16 pat_index, coh_mode;685 u16 pat_index, coh_mode;
423 struct xe_vm *vm;686 struct xe_vm *vm;
424 struct drm_exec exec;687 struct drm_exec exec;
425 int err, attr_type;688 int err, attr_type;
689 bool do_retained;
426 690
427 vm = xe_vm_lookup(xef, args->vm_id);691 vm = xe_vm_lookup(xef, args->vm_id);
428 if (XE_IOCTL_DBG(xe, !vm))692 if (XE_IOCTL_DBG(xe, !vm))
@@ -433,6 +697,25 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil · 4 unmodified lines
433 goto put_vm;697 goto put_vm;
434 }698 }
435 699
700 /* Cache whether we need to write retained, and validate it's initialized to 0 */
701 do_retained = args->type == DRM_XE_VMA_ATTR_PURGEABLE_STATE &&
702 args->purge_state_val.retained_ptr;
703 if (do_retained) {
704 u32 retained;
705 u32 __user *retained_ptr;
706
707 retained_ptr = u64_to_user_ptr(args->purge_state_val.retained_ptr);
708 if (get_user(retained, retained_ptr)) {
709 err = -EFAULT;
710 goto put_vm;
711 }
712
713 if (XE_IOCTL_DBG(xe, retained != 0)) {
714 err = -EINVAL;
715 goto put_vm;
716 }
717 }
718
436 xe_svm_flush(vm);719 xe_svm_flush(vm);
437 720
438 err = down_write_killable(&vm->lock);721 err = down_write_killable(&vm->lock);
@@ -448,7 +731,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil · 9 unmodified lines
448 if (err)731 if (err)
449 goto unlock_vm;732 goto unlock_vm;
450 733
451 err = xe_vm_alloc_madvise_vma(vm, args->start, args->range);734 err = xe_vm_alloc_madvise_vma(vm, madvise_range.addr, args->range);
452 if (err)735 if (err)
453 goto madv_fini;736 goto madv_fini;
454 737
@@ -510,10 +793,18 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil · 55 unmodified lines
510 }793 }
511 794
512 attr_type = array_index_nospec(args->type, ARRAY_SIZE(madvise_funcs));795 attr_type = array_index_nospec(args->type, ARRAY_SIZE(madvise_funcs));
796
797 /* Ensure the madvise function exists for this type */
798 if (!madvise_funcs[attr_type]) {
799 err = -EINVAL;
800 goto err_fini;
801 }
802
513 madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args,803 madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args,
514 &details);804 &details);
515 805
516 err = xe_vm_invalidate_madvise_range(vm, args->start, args->start + args->range);806 err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr,
807 madvise_range.addr + args->range);
517 808
518 if (madvise_range.has_svm_userptr_vmas)809 if (madvise_range.has_svm_userptr_vmas)
519 xe_svm_notifier_unlock(vm);810 xe_svm_notifier_unlock(vm);
@@ -528,6 +819,10 @@ madv_fini: · 8 unmodified lines
528 xe_madvise_details_fini(&details);819 xe_madvise_details_fini(&details);
529unlock_vm:820unlock_vm:
530 up_write(&vm->lock);821 up_write(&vm->lock);
822
823 /* Write retained value to user after releasing all locks */
824 if (!err && do_retained)
825 err = xe_madvise_purgeable_retained_to_user(&details);
531put_vm:826put_vm:
532 xe_vm_put(vm);827 xe_vm_put(vm);
533 return err;828 return err;
drivers/gpu/drm/xe/xe_vm_madvise.h+3−0
@@ -8,8 +8,11 @@ · 7 unmodified lines
8 8
9struct drm_device;9struct drm_device;
10struct drm_file;10struct drm_file;
11struct xe_bo;
11 12
12int xe_vm_madvise_ioctl(struct drm_device *dev, void *data,13int xe_vm_madvise_ioctl(struct drm_device *dev, void *data,
13 struct drm_file *file);14 struct drm_file *file);
14 15
16void xe_bo_recompute_purgeable_state(struct xe_bo *bo);
17
15#endif18#endif
drivers/gpu/drm/xe/xe_vm_types.h+11−0
@@ -96,6 +96,17 @@ struct xe_vma_mem_attr { · 95 unmodified lines
96 * same as default_pat_index unless overwritten by madvise.96 * same as default_pat_index unless overwritten by madvise.
97 */97 */
98 u16 pat_index;98 u16 pat_index;
99
100 /**
101 * @purgeable_state: Purgeable hint for this VMA mapping
102 *
103 * Per-VMA purgeable state from madvise. Valid states are WILLNEED (0)
104 * or DONTNEED (1). Shared BOs require all VMAs to be DONTNEED before
105 * the BO can be purged. PURGED state exists only at BO level.
106 *
107 * Protected by BO dma-resv lock. Set via DRM_IOCTL_XE_MADVISE.
108 */
109 u32 purgeable_state;
99};110};
100 111
101struct xe_vma {112struct xe_vma {
include/uapi/drm/xe_drm.h+69−0
@@ -432,6 +432,7 @@ struct drm_xe_query_config { · 431 unmodified lines
432 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR (1 << 2)432 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR (1 << 2)
433 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT (1 << 3)433 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT (1 << 3)
434 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX (1 << 4)434 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX (1 << 4)
435 #define DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT (1 << 5)
435#define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT 2436#define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT 2
436#define DRM_XE_QUERY_CONFIG_VA_BITS 3437#define DRM_XE_QUERY_CONFIG_VA_BITS 3
437#define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY 4438#define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY 4
@@ -2171,6 +2172,7 @@ struct drm_xe_query_eu_stall { · 1733 unmodified lines
2171 * - DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC: Set preferred memory location.2172 * - DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC: Set preferred memory location.
2172 * - DRM_XE_MEM_RANGE_ATTR_ATOMIC: Set atomic access policy.2173 * - DRM_XE_MEM_RANGE_ATTR_ATOMIC: Set atomic access policy.
2173 * - DRM_XE_MEM_RANGE_ATTR_PAT: Set page attribute table index.2174 * - DRM_XE_MEM_RANGE_ATTR_PAT: Set page attribute table index.
2175 * - DRM_XE_VMA_ATTR_PURGEABLE_STATE: Set purgeable state for BOs.
2174 *2176 *
2175 * Example:2177 * Example:
2176 *2178 *
@@ -2203,6 +2205,7 @@ struct drm_xe_madvise { · 26 unmodified lines
2203#define DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC 02205#define DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC 0
2204#define DRM_XE_MEM_RANGE_ATTR_ATOMIC 12206#define DRM_XE_MEM_RANGE_ATTR_ATOMIC 1
2205#define DRM_XE_MEM_RANGE_ATTR_PAT 22207#define DRM_XE_MEM_RANGE_ATTR_PAT 2
2208#define DRM_XE_VMA_ATTR_PURGEABLE_STATE 3
2206 /** @type: type of attribute */2209 /** @type: type of attribute */
2207 __u32 type;2210 __u32 type;
2208 2211
@@ -2293,6 +2296,72 @@ struct drm_xe_madvise { · 84 unmodified lines
2293 /** @pat_index.reserved: Reserved */2296 /** @pat_index.reserved: Reserved */
2294 __u64 reserved;2297 __u64 reserved;
2295 } pat_index;2298 } pat_index;
2299
2300 /**
2301 * @purge_state_val: Purgeable state configuration
2302 *
2303 * Used when @type == DRM_XE_VMA_ATTR_PURGEABLE_STATE.
2304 *
2305 * Configures the purgeable state of buffer objects in the specified
2306 * virtual address range. This allows applications to hint to the kernel
2307 * about bo's usage patterns for better memory management.
2308 *
2309 * By default all VMAs are in WILLNEED state.
2310 *
2311 * Supported values for @purge_state_val.val:
2312 * - DRM_XE_VMA_PURGEABLE_STATE_WILLNEED (0): Marks BO as needed.
2313 * If the BO was previously purged, the kernel sets the __u32 at
2314 * @retained_ptr to 0 (backing store lost) so the application knows
2315 * it must recreate the BO.
2316 *
2317 * - DRM_XE_VMA_PURGEABLE_STATE_DONTNEED (1): Marks BO as not currently
2318 * needed. Kernel may purge it under memory pressure to reclaim memory.
2319 * Only applies to non-shared BOs. The kernel sets the __u32 at
2320 * @retained_ptr to 1 if the backing store still exists (not yet purged),
2321 * or 0 if it was already purged.
2322 *
2323 * Important: Once marked as DONTNEED, touching the BO's memory
2324 * is undefined behavior. It may succeed temporarily (before the
2325 * kernel purges the backing store) but will suddenly fail once
2326 * the BO transitions to PURGED state.
2327 *
2328 * To transition back: use WILLNEED and check @retained_ptr —
2329 * if 0, backing store was lost and the BO must be recreated.
2330 *
2331 * The following operations are blocked in DONTNEED state to
2332 * prevent the BO from being re-mapped after madvise:
2333 * - New mmap() calls: Fail with -EBUSY
2334 * - VM_BIND operations: Fail with -EBUSY
2335 * - New dma-buf exports: Fail with -EBUSY
2336 * - CPU page faults (existing mmap): Fail with SIGBUS
2337 * - GPU page faults (fault-mode VMs): Fail with -EACCES
2338 */
2339 struct {
2340#define DRM_XE_VMA_PURGEABLE_STATE_WILLNEED 0
2341#define DRM_XE_VMA_PURGEABLE_STATE_DONTNEED 1
2342 /** @purge_state_val.val: value for DRM_XE_VMA_ATTR_PURGEABLE_STATE */
2343 __u32 val;
2344
2345 /** @purge_state_val.pad: MBZ */
2346 __u32 pad;
2347 /**
2348 * @purge_state_val.retained_ptr: Pointer to a __u32 output
2349 * field for backing store status.
2350 *
2351 * Userspace must initialize the __u32 value at this address
2352 * to 0 before the ioctl. Kernel writes a __u32 after the
2353 * operation:
2354 * - 1 if backing store exists (not purged)
2355 * - 0 if backing store was purged
2356 *
2357 * If userspace fails to initialize to 0, ioctl returns -EINVAL.
2358 * This ensures a safe default (0 = assume purged) if kernel
2359 * cannot write the result.
2360 *
2361 * Similar to i915's drm_i915_gem_madvise.retained field.
2362 */
2363 __u64 retained_ptr;
2364 } purge_state_val;
2296 };2365 };
2297 2366
2298 /** @reserved: Reserved */2367 /** @reserved: Reserved */