drm/xe: Convert pinned suspend eviction for exhaustive eviction

Pinned suspend eviction and preparation for eviction validates
system memory for eviction buffers. Do that under a
validation exclusive lock to avoid interfering with other
processes validating system graphics memory.

v2:
- Avoid gotos from within xe_validation_guard().
- Adapt to signature change of xe_validation_guard().

Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Link: https://lore.kernel.org/r/20250908101246.65025-14-thomas.hellstrom@linux.intel.com
This commit is contained in:
Thomas Hellström
2025-09-08 12:12:46 +02:00
parent 1f1541720f
commit 844150c255

View File

@@ -1141,43 +1141,47 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
{
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
struct xe_validation_ctx ctx;
struct drm_exec exec;
struct xe_bo *backup;
int ret = 0;
xe_bo_lock(bo, false);
xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {.exclusive = true}, ret) {
ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
drm_exec_retry_on_contention(&exec);
xe_assert(xe, !ret);
xe_assert(xe, !bo->backup_obj);
xe_assert(xe, !bo->backup_obj);
/*
* Since this is called from the PM notifier we might have raced with
* someone unpinning this after we dropped the pinned list lock and
* grabbing the above bo lock.
*/
if (!xe_bo_is_pinned(bo))
break;
/*
* Since this is called from the PM notifier we might have raced with
* someone unpinning this after we dropped the pinned list lock and
* grabbing the above bo lock.
*/
if (!xe_bo_is_pinned(bo))
goto out_unlock_bo;
if (!xe_bo_is_vram(bo))
break;
if (!xe_bo_is_vram(bo))
goto out_unlock_bo;
if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
break;
if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
goto out_unlock_bo;
backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED, &exec);
if (IS_ERR(backup)) {
drm_exec_retry_on_contention(&exec);
ret = PTR_ERR(backup);
xe_validation_retry_on_oom(&ctx, &ret);
break;
}
backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED, exec);
if (IS_ERR(backup)) {
ret = PTR_ERR(backup);
goto out_unlock_bo;
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
ttm_bo_pin(&backup->ttm);
bo->backup_obj = backup;
}
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
ttm_bo_pin(&backup->ttm);
bo->backup_obj = backup;
out_unlock_bo:
xe_bo_unlock(bo);
return ret;
}
@@ -1203,57 +1207,12 @@ int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
return 0;
}
/**
* xe_bo_evict_pinned() - Evict a pinned VRAM object to system memory
* @bo: The buffer object to move.
*
* On successful completion, the object memory will be moved to system memory.
*
* This is needed to for special handling of pinned VRAM object during
* suspend-resume.
*
* Return: 0 on success. Negative error code on failure.
*/
int xe_bo_evict_pinned(struct xe_bo *bo)
static int xe_bo_evict_pinned_copy(struct xe_bo *bo, struct xe_bo *backup)
{
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
struct drm_exec *exec = XE_VALIDATION_UNIMPLEMENTED;
struct xe_bo *backup = bo->backup_obj;
bool backup_created = false;
struct xe_device *xe = xe_bo_device(bo);
bool unmap = false;
int ret = 0;
xe_bo_lock(bo, false);
if (WARN_ON(!bo->ttm.resource)) {
ret = -EINVAL;
goto out_unlock_bo;
}
if (WARN_ON(!xe_bo_is_pinned(bo))) {
ret = -EINVAL;
goto out_unlock_bo;
}
if (!xe_bo_is_vram(bo))
goto out_unlock_bo;
if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
goto out_unlock_bo;
if (!backup) {
backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED, exec);
if (IS_ERR(backup)) {
ret = PTR_ERR(backup);
goto out_unlock_bo;
}
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
backup_created = true;
}
if (xe_bo_is_user(bo) || (bo->flags & XE_BO_FLAG_PINNED_LATE_RESTORE)) {
struct xe_migrate *migrate;
struct dma_fence *fence;
@@ -1286,7 +1245,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
if (iosys_map_is_null(&bo->vmap)) {
ret = xe_bo_vmap(bo);
if (ret)
goto out_backup;
goto out_vunmap;
unmap = true;
}
@@ -1296,15 +1255,78 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
if (!bo->backup_obj)
bo->backup_obj = backup;
out_backup:
out_vunmap:
xe_bo_vunmap(backup);
if (ret && backup_created)
xe_bo_put(backup);
out_unlock_bo:
out_backup:
if (unmap)
xe_bo_vunmap(bo);
xe_bo_unlock(bo);
return ret;
}
/**
* xe_bo_evict_pinned() - Evict a pinned VRAM object to system memory
* @bo: The buffer object to move.
*
* On successful completion, the object memory will be moved to system memory.
*
* This is needed to for special handling of pinned VRAM object during
* suspend-resume.
*
* Return: 0 on success. Negative error code on failure.
*/
int xe_bo_evict_pinned(struct xe_bo *bo)
{
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
struct xe_validation_ctx ctx;
struct drm_exec exec;
struct xe_bo *backup = bo->backup_obj;
bool backup_created = false;
int ret = 0;
xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {.exclusive = true}, ret) {
ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
drm_exec_retry_on_contention(&exec);
xe_assert(xe, !ret);
if (WARN_ON(!bo->ttm.resource)) {
ret = -EINVAL;
break;
}
if (WARN_ON(!xe_bo_is_pinned(bo))) {
ret = -EINVAL;
break;
}
if (!xe_bo_is_vram(bo))
break;
if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
break;
if (!backup) {
backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL,
xe_bo_size(bo),
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED, &exec);
if (IS_ERR(backup)) {
drm_exec_retry_on_contention(&exec);
ret = PTR_ERR(backup);
xe_validation_retry_on_oom(&ctx, &ret);
break;
}
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
backup_created = true;
}
ret = xe_bo_evict_pinned_copy(bo, backup);
}
if (ret && backup_created)
xe_bo_put(backup);
return ret;
}