Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/ttm, drm/amdgpu: Allow the driver some control over swapping

We are calling the eviction_valuable driver callback at eviction time to
determine whether we actually can evict a buffer object.
The upcoming i915 TTM backend needs the same functionality for swapout,
and that might actually be beneficial to other drivers as well.

Add an eviction_valuable call also in the swapout path. Try to keep the
current behaviour for all drivers by returning true if the buffer object
is already in the TTM_PL_SYSTEM placement. We change behaviour for the
case where a buffer object is in a TT backed placement when swapped out,
in which case the drivers normal eviction_valuable path is run.

Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Acked-by: Christian König <christian.koenig@amd.com>
Link: https://lore.kernel.org/r/20210602083818.241793-8-thomas.hellstrom@linux.intel.com
Link: https://patchwork.freedesktop.org/patch/msgid/20210602083818.241793-8-thomas.hellstrom@linux.intel.com

+34 -16
+4
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
··· 1331 1331 struct dma_fence *f; 1332 1332 int i; 1333 1333 1334 + /* Swapout? */ 1335 + if (bo->resource->mem_type == TTM_PL_SYSTEM) 1336 + return true; 1337 + 1334 1338 if (bo->type == ttm_bo_type_kernel && 1335 1339 !amdgpu_vm_evictable(ttm_to_amdgpu_bo(bo))) 1336 1340 return false;
+30 -16
drivers/gpu/drm/ttm/ttm_bo.c
··· 538 538 bool ttm_bo_eviction_valuable(struct ttm_buffer_object *bo, 539 539 const struct ttm_place *place) 540 540 { 541 + dma_resv_assert_held(bo->base.resv); 542 + if (bo->resource->mem_type == TTM_PL_SYSTEM) 543 + return true; 544 + 541 545 /* Don't evict this BO if it's outside of the 542 546 * requested placement range 543 547 */ ··· 564 560 * b. Otherwise, trylock it. 565 561 */ 566 562 static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo, 567 - struct ttm_operation_ctx *ctx, bool *locked, bool *busy) 563 + struct ttm_operation_ctx *ctx, 564 + const struct ttm_place *place, 565 + bool *locked, bool *busy) 568 566 { 569 567 bool ret = false; 570 568 ··· 582 576 *locked = ret; 583 577 if (busy) 584 578 *busy = !ret; 579 + } 580 + 581 + if (ret && place && !bo->bdev->funcs->eviction_valuable(bo, place)) { 582 + ret = false; 583 + if (*locked) { 584 + dma_resv_unlock(bo->base.resv); 585 + *locked = false; 586 + } 585 587 } 586 588 587 589 return ret; ··· 646 632 list_for_each_entry(bo, &man->lru[i], lru) { 647 633 bool busy; 648 634 649 - if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked, 650 - &busy)) { 635 + if (!ttm_bo_evict_swapout_allowable(bo, ctx, place, 636 + &locked, &busy)) { 651 637 if (busy && !busy_bo && ticket != 652 638 dma_resv_locking_ctx(bo->base.resv)) 653 639 busy_bo = bo; 654 640 continue; 655 641 } 656 642 657 - if (place && !bdev->funcs->eviction_valuable(bo, 658 - place)) { 659 - if (locked) 660 - dma_resv_unlock(bo->base.resv); 661 - continue; 662 - } 663 643 if (!ttm_bo_get_unless_zero(bo)) { 664 644 if (locked) 665 645 dma_resv_unlock(bo->base.resv); ··· 1124 1116 int ttm_bo_swapout(struct ttm_buffer_object *bo, struct ttm_operation_ctx *ctx, 1125 1117 gfp_t gfp_flags) 1126 1118 { 1119 + struct ttm_place place; 1127 1120 bool locked; 1128 1121 int ret; 1129 1122 1130 - if (!ttm_bo_evict_swapout_allowable(bo, ctx, &locked, NULL)) 1123 + /* 1124 + * While the bo may already reside in SYSTEM placement, set 1125 + * SYSTEM as new placement to cover also the move further below. 1126 + * The driver may use the fact that we're moving from SYSTEM 1127 + * as an indication that we're about to swap out. 1128 + */ 1129 + memset(&place, 0, sizeof(place)); 1130 + place.mem_type = TTM_PL_SYSTEM; 1131 + if (!ttm_bo_evict_swapout_allowable(bo, ctx, &place, &locked, NULL)) 1131 1132 return -EBUSY; 1132 1133 1133 1134 if (!ttm_bo_get_unless_zero(bo)) { ··· 1161 1144 if (bo->resource->mem_type != TTM_PL_SYSTEM) { 1162 1145 struct ttm_operation_ctx ctx = { false, false }; 1163 1146 struct ttm_resource *evict_mem; 1164 - struct ttm_place place, hop; 1147 + struct ttm_place hop; 1165 1148 1166 - memset(&place, 0, sizeof(place)); 1167 1149 memset(&hop, 0, sizeof(hop)); 1168 - 1169 - place.mem_type = TTM_PL_SYSTEM; 1170 - 1171 1150 ret = ttm_resource_alloc(bo, &place, &evict_mem); 1172 1151 if (unlikely(ret)) 1173 1152 goto out; ··· 1191 1178 if (bo->bdev->funcs->swap_notify) 1192 1179 bo->bdev->funcs->swap_notify(bo); 1193 1180 1194 - ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags); 1181 + if (ttm_tt_is_populated(bo->ttm)) 1182 + ret = ttm_tt_swapout(bo->bdev, bo->ttm, gfp_flags); 1195 1183 out: 1196 1184 1197 1185 /*