Skip to content

Commit 86f69c2

Browse files
committed
drm/xe: use backup object for pinned save/restore
Currently we move pinned objects, relying on the fact that the lpfn/fpfn will force the placement to occupy the same pages when restoring. However this then limits all such pinned objects to be contig underneath. In addition it is likely a little fragile moving pinned objects in the first place. Rather than moving such objects rather copy the page contents to a secondary system memory object, that way the VRAM pages never move and remain pinned. This also opens the door for eventually having non-contig pinned objects that can also be saved/restored using blitter. v2: - Make sure to drop the fence ref. - Handle NULL bo->migrate. v3: - Ensure we add the copy fence to the BOs, otherwise backup_obj can be freed before pipelined copy finishes. v4: - Rebase on newly added apply-to-pinned infra. Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/1182 Signed-off-by: Matthew Auld <matthew.auld@intel.com> Cc: Satyanarayana K V P <satyanarayana.k.v.p@intel.com> Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com> Cc: Matthew Brost <matthew.brost@intel.com> Reviewed-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com> Link: https://lore.kernel.org/r/20250403102440.266113-10-matthew.auld@intel.com
1 parent 7654d51 commit 86f69c2

File tree

3 files changed

+167
-152
lines changed

3 files changed

+167
-152
lines changed

drivers/gpu/drm/xe/xe_bo.c

Lines changed: 165 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -916,79 +916,44 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
916916
xe_pm_runtime_get_noresume(xe);
917917
}
918918

919-
if (xe_bo_is_pinned(bo) && !xe_bo_is_user(bo)) {
920-
/*
921-
* Kernel memory that is pinned should only be moved on suspend
922-
* / resume, some of the pinned memory is required for the
923-
* device to resume / use the GPU to move other evicted memory
924-
* (user memory) around. This likely could be optimized a bit
925-
* further where we find the minimum set of pinned memory
926-
* required for resume but for simplity doing a memcpy for all
927-
* pinned memory.
928-
*/
929-
ret = xe_bo_vmap(bo);
930-
if (!ret) {
931-
ret = ttm_bo_move_memcpy(ttm_bo, ctx, new_mem);
932-
933-
/* Create a new VMAP once kernel BO back in VRAM */
934-
if (!ret && resource_is_vram(new_mem)) {
935-
struct xe_vram_region *vram = res_to_mem_region(new_mem);
936-
void __iomem *new_addr = vram->mapping +
937-
(new_mem->start << PAGE_SHIFT);
919+
if (move_lacks_source) {
920+
u32 flags = 0;
938921

939-
if (XE_WARN_ON(new_mem->start == XE_BO_INVALID_OFFSET)) {
940-
ret = -EINVAL;
941-
xe_pm_runtime_put(xe);
942-
goto out;
943-
}
922+
if (mem_type_is_vram(new_mem->mem_type))
923+
flags |= XE_MIGRATE_CLEAR_FLAG_FULL;
924+
else if (handle_system_ccs)
925+
flags |= XE_MIGRATE_CLEAR_FLAG_CCS_DATA;
944926

945-
xe_assert(xe, new_mem->start ==
946-
bo->placements->fpfn);
947-
948-
iosys_map_set_vaddr_iomem(&bo->vmap, new_addr);
949-
}
950-
}
927+
fence = xe_migrate_clear(migrate, bo, new_mem, flags);
951928
} else {
952-
if (move_lacks_source) {
953-
u32 flags = 0;
954-
955-
if (mem_type_is_vram(new_mem->mem_type))
956-
flags |= XE_MIGRATE_CLEAR_FLAG_FULL;
957-
else if (handle_system_ccs)
958-
flags |= XE_MIGRATE_CLEAR_FLAG_CCS_DATA;
959-
960-
fence = xe_migrate_clear(migrate, bo, new_mem, flags);
961-
}
962-
else
963-
fence = xe_migrate_copy(migrate, bo, bo, old_mem,
964-
new_mem, handle_system_ccs);
965-
if (IS_ERR(fence)) {
966-
ret = PTR_ERR(fence);
967-
xe_pm_runtime_put(xe);
968-
goto out;
969-
}
970-
if (!move_lacks_source) {
971-
ret = ttm_bo_move_accel_cleanup(ttm_bo, fence, evict,
972-
true, new_mem);
973-
if (ret) {
974-
dma_fence_wait(fence, false);
975-
ttm_bo_move_null(ttm_bo, new_mem);
976-
ret = 0;
977-
}
978-
} else {
979-
/*
980-
* ttm_bo_move_accel_cleanup() may blow up if
981-
* bo->resource == NULL, so just attach the
982-
* fence and set the new resource.
983-
*/
984-
dma_resv_add_fence(ttm_bo->base.resv, fence,
985-
DMA_RESV_USAGE_KERNEL);
929+
fence = xe_migrate_copy(migrate, bo, bo, old_mem, new_mem,
930+
handle_system_ccs);
931+
}
932+
if (IS_ERR(fence)) {
933+
ret = PTR_ERR(fence);
934+
xe_pm_runtime_put(xe);
935+
goto out;
936+
}
937+
if (!move_lacks_source) {
938+
ret = ttm_bo_move_accel_cleanup(ttm_bo, fence, evict, true,
939+
new_mem);
940+
if (ret) {
941+
dma_fence_wait(fence, false);
986942
ttm_bo_move_null(ttm_bo, new_mem);
943+
ret = 0;
987944
}
988-
989-
dma_fence_put(fence);
945+
} else {
946+
/*
947+
* ttm_bo_move_accel_cleanup() may blow up if
948+
* bo->resource == NULL, so just attach the
949+
* fence and set the new resource.
950+
*/
951+
dma_resv_add_fence(ttm_bo->base.resv, fence,
952+
DMA_RESV_USAGE_KERNEL);
953+
ttm_bo_move_null(ttm_bo, new_mem);
990954
}
991955

956+
dma_fence_put(fence);
992957
xe_pm_runtime_put(xe);
993958

994959
out:
@@ -1125,59 +1090,90 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
11251090
*/
11261091
int xe_bo_evict_pinned(struct xe_bo *bo)
11271092
{
1128-
struct ttm_place place = {
1129-
.mem_type = XE_PL_TT,
1130-
};
1131-
struct ttm_placement placement = {
1132-
.placement = &place,
1133-
.num_placement = 1,
1134-
};
1135-
struct ttm_operation_ctx ctx = {
1136-
.interruptible = false,
1137-
.gfp_retry_mayfail = true,
1138-
};
1139-
struct ttm_resource *new_mem;
1140-
int ret;
1093+
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
1094+
struct xe_bo *backup;
1095+
bool unmap = false;
1096+
int ret = 0;
11411097

1142-
xe_bo_assert_held(bo);
1098+
xe_bo_lock(bo, false);
11431099

1144-
if (WARN_ON(!bo->ttm.resource))
1145-
return -EINVAL;
1100+
if (WARN_ON(!bo->ttm.resource)) {
1101+
ret = -EINVAL;
1102+
goto out_unlock_bo;
1103+
}
11461104

1147-
if (WARN_ON(!xe_bo_is_pinned(bo)))
1148-
return -EINVAL;
1105+
if (WARN_ON(!xe_bo_is_pinned(bo))) {
1106+
ret = -EINVAL;
1107+
goto out_unlock_bo;
1108+
}
11491109

11501110
if (!xe_bo_is_vram(bo))
1151-
return 0;
1111+
goto out_unlock_bo;
11521112

1153-
ret = ttm_bo_mem_space(&bo->ttm, &placement, &new_mem, &ctx);
1154-
if (ret)
1155-
return ret;
1113+
backup = xe_bo_create_locked(xe, NULL, NULL, bo->size, ttm_bo_type_kernel,
1114+
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
1115+
XE_BO_FLAG_PINNED);
1116+
if (IS_ERR(backup)) {
1117+
ret = PTR_ERR(backup);
1118+
goto out_unlock_bo;
1119+
}
1120+
1121+
if (xe_bo_is_user(bo)) {
1122+
struct xe_migrate *migrate;
1123+
struct dma_fence *fence;
1124+
1125+
if (bo->tile)
1126+
migrate = bo->tile->migrate;
1127+
else
1128+
migrate = mem_type_to_migrate(xe, bo->ttm.resource->mem_type);
1129+
1130+
ret = dma_resv_reserve_fences(bo->ttm.base.resv, 1);
1131+
if (ret)
1132+
goto out_backup;
1133+
1134+
ret = dma_resv_reserve_fences(backup->ttm.base.resv, 1);
1135+
if (ret)
1136+
goto out_backup;
11561137

1157-
if (!bo->ttm.ttm) {
1158-
bo->ttm.ttm = xe_ttm_tt_create(&bo->ttm, 0);
1159-
if (!bo->ttm.ttm) {
1160-
ret = -ENOMEM;
1161-
goto err_res_free;
1138+
fence = xe_migrate_copy(migrate, bo, backup, bo->ttm.resource,
1139+
backup->ttm.resource, false);
1140+
if (IS_ERR(fence)) {
1141+
ret = PTR_ERR(fence);
1142+
goto out_backup;
11621143
}
1163-
}
11641144

1165-
ret = ttm_bo_populate(&bo->ttm, &ctx);
1166-
if (ret)
1167-
goto err_res_free;
1145+
dma_resv_add_fence(bo->ttm.base.resv, fence,
1146+
DMA_RESV_USAGE_KERNEL);
1147+
dma_resv_add_fence(backup->ttm.base.resv, fence,
1148+
DMA_RESV_USAGE_KERNEL);
1149+
dma_fence_put(fence);
1150+
} else {
1151+
ret = xe_bo_vmap(backup);
1152+
if (ret)
1153+
goto out_backup;
11681154

1169-
ret = dma_resv_reserve_fences(bo->ttm.base.resv, 1);
1170-
if (ret)
1171-
goto err_res_free;
1155+
if (iosys_map_is_null(&bo->vmap)) {
1156+
ret = xe_bo_vmap(bo);
1157+
if (ret)
1158+
goto out_backup;
1159+
unmap = true;
1160+
}
11721161

1173-
ret = xe_bo_move(&bo->ttm, false, &ctx, new_mem, NULL);
1174-
if (ret)
1175-
goto err_res_free;
1162+
xe_map_memcpy_from(xe, backup->vmap.vaddr, &bo->vmap, 0,
1163+
bo->size);
1164+
}
11761165

1177-
return 0;
1166+
bo->backup_obj = backup;
11781167

1179-
err_res_free:
1180-
ttm_resource_free(&bo->ttm, &new_mem);
1168+
out_backup:
1169+
xe_bo_vunmap(backup);
1170+
xe_bo_unlock(backup);
1171+
if (ret)
1172+
xe_bo_put(backup);
1173+
out_unlock_bo:
1174+
if (unmap)
1175+
xe_bo_vunmap(bo);
1176+
xe_bo_unlock(bo);
11811177
return ret;
11821178
}
11831179

@@ -1198,47 +1194,82 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
11981194
.interruptible = false,
11991195
.gfp_retry_mayfail = false,
12001196
};
1201-
struct ttm_resource *new_mem;
1202-
struct ttm_place *place = &bo->placements[0];
1197+
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
1198+
struct xe_bo *backup = bo->backup_obj;
1199+
bool unmap = false;
12031200
int ret;
12041201

1205-
xe_bo_assert_held(bo);
1202+
if (!backup)
1203+
return 0;
12061204

1207-
if (WARN_ON(!bo->ttm.resource))
1208-
return -EINVAL;
1205+
xe_bo_lock(backup, false);
12091206

1210-
if (WARN_ON(!xe_bo_is_pinned(bo)))
1211-
return -EINVAL;
1207+
ret = ttm_bo_validate(&backup->ttm, &backup->placement, &ctx);
1208+
if (ret)
1209+
goto out_backup;
12121210

1213-
if (WARN_ON(xe_bo_is_vram(bo)))
1214-
return -EINVAL;
1211+
if (WARN_ON(!dma_resv_trylock(bo->ttm.base.resv))) {
1212+
ret = -EBUSY;
1213+
goto out_backup;
1214+
}
12151215

1216-
if (WARN_ON(!bo->ttm.ttm && !xe_bo_is_stolen(bo)))
1217-
return -EINVAL;
1216+
if (xe_bo_is_user(bo)) {
1217+
struct xe_migrate *migrate;
1218+
struct dma_fence *fence;
12181219

1219-
if (!mem_type_is_vram(place->mem_type))
1220-
return 0;
1220+
if (bo->tile)
1221+
migrate = bo->tile->migrate;
1222+
else
1223+
migrate = mem_type_to_migrate(xe, bo->ttm.resource->mem_type);
12211224

1222-
ret = ttm_bo_mem_space(&bo->ttm, &bo->placement, &new_mem, &ctx);
1223-
if (ret)
1224-
return ret;
1225+
ret = dma_resv_reserve_fences(bo->ttm.base.resv, 1);
1226+
if (ret)
1227+
goto out_unlock_bo;
12251228

1226-
ret = ttm_bo_populate(&bo->ttm, &ctx);
1227-
if (ret)
1228-
goto err_res_free;
1229+
ret = dma_resv_reserve_fences(backup->ttm.base.resv, 1);
1230+
if (ret)
1231+
goto out_unlock_bo;
12291232

1230-
ret = dma_resv_reserve_fences(bo->ttm.base.resv, 1);
1231-
if (ret)
1232-
goto err_res_free;
1233+
fence = xe_migrate_copy(migrate, backup, bo,
1234+
backup->ttm.resource, bo->ttm.resource,
1235+
false);
1236+
if (IS_ERR(fence)) {
1237+
ret = PTR_ERR(fence);
1238+
goto out_unlock_bo;
1239+
}
12331240

1234-
ret = xe_bo_move(&bo->ttm, false, &ctx, new_mem, NULL);
1235-
if (ret)
1236-
goto err_res_free;
1241+
dma_resv_add_fence(bo->ttm.base.resv, fence,
1242+
DMA_RESV_USAGE_KERNEL);
1243+
dma_resv_add_fence(backup->ttm.base.resv, fence,
1244+
DMA_RESV_USAGE_KERNEL);
1245+
dma_fence_put(fence);
1246+
} else {
1247+
ret = xe_bo_vmap(backup);
1248+
if (ret)
1249+
goto out_unlock_bo;
12371250

1238-
return 0;
1251+
if (iosys_map_is_null(&bo->vmap)) {
1252+
ret = xe_bo_vmap(bo);
1253+
if (ret)
1254+
goto out_unlock_bo;
1255+
unmap = true;
1256+
}
1257+
1258+
xe_map_memcpy_to(xe, &bo->vmap, 0, backup->vmap.vaddr,
1259+
bo->size);
1260+
}
12391261

1240-
err_res_free:
1241-
ttm_resource_free(&bo->ttm, &new_mem);
1262+
bo->backup_obj = NULL;
1263+
1264+
out_unlock_bo:
1265+
if (unmap)
1266+
xe_bo_vunmap(bo);
1267+
xe_bo_unlock(bo);
1268+
out_backup:
1269+
xe_bo_vunmap(backup);
1270+
xe_bo_unlock(backup);
1271+
if (!bo->backup_obj)
1272+
xe_bo_put(backup);
12421273
return ret;
12431274
}
12441275

@@ -2195,22 +2226,6 @@ int xe_bo_pin(struct xe_bo *bo)
21952226
if (err)
21962227
return err;
21972228

2198-
/*
2199-
* For pinned objects in on DGFX, which are also in vram, we expect
2200-
* these to be in contiguous VRAM memory. Required eviction / restore
2201-
* during suspend / resume (force restore to same physical address).
2202-
*/
2203-
if (IS_DGFX(xe) && !(IS_ENABLED(CONFIG_DRM_XE_DEBUG) &&
2204-
bo->flags & XE_BO_FLAG_INTERNAL_TEST)) {
2205-
if (mem_type_is_vram(place->mem_type)) {
2206-
xe_assert(xe, place->flags & TTM_PL_FLAG_CONTIGUOUS);
2207-
2208-
place->fpfn = (xe_bo_addr(bo, 0, PAGE_SIZE) -
2209-
vram_region_gpu_offset(bo->ttm.resource)) >> PAGE_SHIFT;
2210-
place->lpfn = place->fpfn + (bo->size >> PAGE_SHIFT);
2211-
}
2212-
}
2213-
22142229
if (mem_type_is_vram(place->mem_type) || bo->flags & XE_BO_FLAG_GGTT) {
22152230
spin_lock(&xe->pinned.lock);
22162231
list_add_tail(&bo->pinned_link, &xe->pinned.kernel_bo_present);

drivers/gpu/drm/xe/xe_bo_evict.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,12 @@ static int xe_bo_apply_to_pinned(struct xe_device *xe,
3131
list_move_tail(&bo->pinned_link, &still_in_list);
3232
spin_unlock(&xe->pinned.lock);
3333

34-
xe_bo_lock(bo, false);
3534
ret = pinned_fn(bo);
3635
if (ret && pinned_list != new_list) {
3736
spin_lock(&xe->pinned.lock);
3837
list_move(&bo->pinned_link, pinned_list);
3938
spin_unlock(&xe->pinned.lock);
4039
}
41-
xe_bo_unlock(bo);
4240
xe_bo_put(bo);
4341
spin_lock(&xe->pinned.lock);
4442
}

drivers/gpu/drm/xe/xe_bo_types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ struct xe_vm;
2828
struct xe_bo {
2929
/** @ttm: TTM base buffer object */
3030
struct ttm_buffer_object ttm;
31+
/** @backup_obj: The backup object when pinned and suspended (vram only) */
32+
struct xe_bo *backup_obj;
3133
/** @size: Size of this buffer object */
3234
size_t size;
3335
/** @flags: flags for this buffer object */

0 commit comments

Comments
 (0)