Commit 844150c2 authored by Thomas Hellström's avatar Thomas Hellström
Browse files

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: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: default avatarMatthew Brost <matthew.brost@intel.com>
Link: https://lore.kernel.org/r/20250908101246.65025-14-thomas.hellstrom@linux.intel.com
parent 1f154172
Loading
Loading
Loading
Loading
+103 −81
Original line number Diff line number Diff line
@@ -1141,12 +1141,15 @@ 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);

		/*
@@ -1155,29 +1158,30 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
		 * grabbing the above bo lock.
		 */
		if (!xe_bo_is_pinned(bo))
		goto out_unlock_bo;
			break;

		if (!xe_bo_is_vram(bo))
		goto out_unlock_bo;
			break;

		if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
		goto out_unlock_bo;
			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);
					   XE_BO_FLAG_PINNED, &exec);
		if (IS_ERR(backup)) {
			drm_exec_retry_on_contention(&exec);
			ret = PTR_ERR(backup);
		goto out_unlock_bo;
			xe_validation_retry_on_oom(&ctx, &ret);
			break;
		}

		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;
}