On Tue, Oct 20, 2026 at 12:05:04PM +0200, Thomas Hellström wrote:
> When evicting user BOs from VRAM at suspend time, allocating system
> memory for the eviction may currently invoke the OOM killer. Under
> memory pressure it is preferable to abort the suspend and return
> -ENOMEM rather than killing processes.
>
> TTM's ttm_resource_manager_evict_all() uses a default operation
> context, which doesn't allow the caller to request
> __GFP_RETRY_MAYFAIL allocations. Introduce
> ttm_resource_manager_evict_all_ctx() taking a caller-supplied
> struct ttm_operation_ctx, keeping ttm_resource_manager_evict_all()
> as an exported wrapper using a default context so that existing
> users are unaffected. Also honor the ctx interruptible setting when
> waiting for the eviction fences.
>
> Use the new function from xe_bo_evict_all_user() with
> gfp_retry_mayfail set.
>
> Note that the PM notifier eviction is best-effort and ignores errors.
> Any remaining BOs are evicted again from the .suspend() callback,
> where an -ENOMEM might then cause the suspend to be aborted.
>
> Fixes: c6a4d46ec1d7 ("drm/xe: evict user memory in PM notifier")
> Cc: Matthew Auld <[email protected]>
> Cc: Matthew Brost <[email protected]>
Reviewed-by: Matthew Brost <[email protected]>
> Cc: Rodrigo Vivi <[email protected]>
> Cc: Natalie Vock <[email protected]>
> Cc: Arun Pravin <[email protected]>
> Cc: [email protected]
> Cc: [email protected]
> Cc: <[email protected]> # v6.16+
> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/9615
> Assisted-by: LLM
> Signed-off-by: Thomas Hellström <[email protected]>
> ---
> drivers/gpu/drm/ttm/ttm_resource.c | 37 +++++++++++++++++++++++-------
> drivers/gpu/drm/xe/xe_bo_evict.c | 5 +++-
> include/drm/ttm/ttm_resource.h | 5 ++++
> 3 files changed, 38 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/ttm/ttm_resource.c
> b/drivers/gpu/drm/ttm/ttm_resource.c
> index 4e6d3d658d85..5296b32a2e92 100644
> --- a/drivers/gpu/drm/ttm/ttm_resource.c
> +++ b/drivers/gpu/drm/ttm/ttm_resource.c
> @@ -568,24 +568,26 @@ void ttm_resource_manager_init(struct
> ttm_resource_manager *man,
> }
> EXPORT_SYMBOL(ttm_resource_manager_init);
>
> -/*
> - * ttm_resource_manager_evict_all
> - *
> +/**
> + * ttm_resource_manager_evict_all_ctx() - Evict all objects from a manager
> * @bdev: device to use
> * @man: manager to use
> + * @ctx: operation context for the eviction
> *
> * Evict all the objects out of a memory manager until it is empty.
> * Part of memory manager cleanup sequence.
> + *
> + * Return: 0 on success, negative error code on failure.
> */
> -int ttm_resource_manager_evict_all(struct ttm_device *bdev,
> - struct ttm_resource_manager *man)
> +int ttm_resource_manager_evict_all_ctx(struct ttm_device *bdev,
> + struct ttm_resource_manager *man,
> + struct ttm_operation_ctx *ctx)
> {
> - struct ttm_operation_ctx ctx = { };
> struct dma_fence *fence;
> int ret, i;
>
> do {
> - ret = ttm_bo_evict_first(bdev, man, &ctx);
> + ret = ttm_bo_evict_first(bdev, man, ctx);
> cond_resched();
> } while (!ret);
>
> @@ -600,7 +602,7 @@ int ttm_resource_manager_evict_all(struct ttm_device
> *bdev,
> if (fence && !dma_fence_is_signaled(fence)) {
> dma_fence_get(fence);
> spin_unlock(&man->eviction_lock);
> - ret = dma_fence_wait(fence, false);
> + ret = dma_fence_wait(fence, ctx->interruptible);
> dma_fence_put(fence);
> if (ret)
> return ret;
> @@ -611,6 +613,25 @@ int ttm_resource_manager_evict_all(struct ttm_device
> *bdev,
>
> return ret;
> }
> +EXPORT_SYMBOL(ttm_resource_manager_evict_all_ctx);
> +
> +/**
> + * ttm_resource_manager_evict_all() - Evict all objects from a manager
> + * @bdev: device to use
> + * @man: manager to use
> + *
> + * Same as ttm_resource_manager_evict_all_ctx() using a default,
> + * non-interruptible operation context.
> + *
> + * Return: 0 on success, negative error code on failure.
> + */
> +int ttm_resource_manager_evict_all(struct ttm_device *bdev,
> + struct ttm_resource_manager *man)
> +{
> + struct ttm_operation_ctx ctx = { };
> +
> + return ttm_resource_manager_evict_all_ctx(bdev, man, &ctx);
> +}
> EXPORT_SYMBOL(ttm_resource_manager_evict_all);
>
> /**
> diff --git a/drivers/gpu/drm/xe/xe_bo_evict.c
> b/drivers/gpu/drm/xe/xe_bo_evict.c
> index 7661fca7f278..a37316a27573 100644
> --- a/drivers/gpu/drm/xe/xe_bo_evict.c
> +++ b/drivers/gpu/drm/xe/xe_bo_evict.c
> @@ -114,6 +114,9 @@ void xe_bo_notifier_unprepare_all_pinned(struct xe_device
> *xe)
> */
> int xe_bo_evict_all_user(struct xe_device *xe)
> {
> + struct ttm_operation_ctx ctx = {
> + .gfp_retry_mayfail = true,
> + };
> struct ttm_device *bdev = &xe->ttm;
> u32 mem_type;
> int ret;
> @@ -135,7 +138,7 @@ int xe_bo_evict_all_user(struct xe_device *xe)
> continue;
>
> if (man) {
> - ret = ttm_resource_manager_evict_all(bdev, man);
> + ret = ttm_resource_manager_evict_all_ctx(bdev, man,
> &ctx);
> if (ret)
> return ret;
> }
> diff --git a/include/drm/ttm/ttm_resource.h b/include/drm/ttm/ttm_resource.h
> index 714c533622c2..6cf9187a12eb 100644
> --- a/include/drm/ttm/ttm_resource.h
> +++ b/include/drm/ttm/ttm_resource.h
> @@ -42,6 +42,7 @@ struct dmem_cgroup_device;
> struct dmem_cgroup_region;
> struct drm_printer;
> struct ttm_device;
> +struct ttm_operation_ctx;
> struct ttm_resource_manager;
> struct ttm_resource;
> struct ttm_place;
> @@ -488,6 +489,10 @@ void ttm_resource_manager_set_dmem_region(struct
> ttm_resource_manager *man,
> int ttm_resource_manager_dmem_reclaim(struct dmem_cgroup_pool_state *pool,
> u64 target_bytes, void *priv);
>
> +int ttm_resource_manager_evict_all_ctx(struct ttm_device *bdev,
> + struct ttm_resource_manager *man,
> + struct ttm_operation_ctx *ctx);
> +
> int ttm_resource_manager_evict_all(struct ttm_device *bdev,
> struct ttm_resource_manager *man);
>
> --
> 2.56.0
>