Skip to content

Commit f3bcfd0

Browse files
author
Thomas Hellström
committed
drm/ttm: Add a macro to perform LRU iteration
Following the design direction communicated here: https://lore.kernel.org/linux-mm/[email protected]/T/#ma918844aa8a6efe8768fdcda0c6590d5c93850c9 Export a LRU walker for driver shrinker use. The walker initially supports only trylocking, since that's the method used by shrinkes. The walker makes use of scoped_guard() to allow exiting from the LRU walk loop without performing any explicit unlocking or cleanup. v8: - Split out from another patch. - Use a struct for bool arguments to increase readability (Matt Brost). - Unmap user-space cpu-mappings before shrinking pages. - Explain non-fatal error codes (Matt Brost) v10: - Instead of using the existing helper, Wrap the interface inside out and provide a loop to de-midlayer things the LRU iteration (Christian König). - Removing the R-B by Matt Brost since the patch was significantly changed. v11: - Split the patch up to include just the LRU walk helper. v12: - Indent after scoped_guard() (Matt Brost) v15: - Adapt to new definition of scoped_guard() Signed-off-by: Thomas Hellström <[email protected]> Reviewed-by: Matthew Brost <[email protected]> Acked-by: Dave Airlie <[email protected]> Acked-by: Christian König <[email protected]> Link: https://lore.kernel.org/intel-xe/[email protected]
1 parent 8ae875f commit f3bcfd0

File tree

2 files changed

+208
-4
lines changed

2 files changed

+208
-4
lines changed

drivers/gpu/drm/ttm/ttm_bo_util.c

Lines changed: 136 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -769,12 +769,10 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo)
769769
return ret;
770770
}
771771

772-
static bool ttm_lru_walk_trylock(struct ttm_lru_walk *walk,
772+
static bool ttm_lru_walk_trylock(struct ttm_operation_ctx *ctx,
773773
struct ttm_buffer_object *bo,
774774
bool *needs_unlock)
775775
{
776-
struct ttm_operation_ctx *ctx = walk->ctx;
777-
778776
*needs_unlock = false;
779777

780778
if (dma_resv_trylock(bo->base.resv)) {
@@ -877,7 +875,7 @@ s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev,
877875
* since if we do it the other way around, and the trylock fails,
878876
* we need to drop the lru lock to put the bo.
879877
*/
880-
if (ttm_lru_walk_trylock(walk, bo, &bo_needs_unlock))
878+
if (ttm_lru_walk_trylock(walk->ctx, bo, &bo_needs_unlock))
881879
bo_locked = true;
882880
else if (!walk->ticket || walk->ctx->no_wait_gpu ||
883881
walk->trylock_only)
@@ -920,3 +918,137 @@ s64 ttm_lru_walk_for_evict(struct ttm_lru_walk *walk, struct ttm_device *bdev,
920918

921919
return progress;
922920
}
921+
EXPORT_SYMBOL(ttm_lru_walk_for_evict);
922+
923+
static void ttm_bo_lru_cursor_cleanup_bo(struct ttm_bo_lru_cursor *curs)
924+
{
925+
struct ttm_buffer_object *bo = curs->bo;
926+
927+
if (bo) {
928+
if (curs->needs_unlock)
929+
dma_resv_unlock(bo->base.resv);
930+
ttm_bo_put(bo);
931+
curs->bo = NULL;
932+
}
933+
}
934+
935+
/**
936+
* ttm_bo_lru_cursor_fini() - Stop using a struct ttm_bo_lru_cursor
937+
* and clean up any iteration it was used for.
938+
* @curs: The cursor.
939+
*/
940+
void ttm_bo_lru_cursor_fini(struct ttm_bo_lru_cursor *curs)
941+
{
942+
spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock;
943+
944+
ttm_bo_lru_cursor_cleanup_bo(curs);
945+
spin_lock(lru_lock);
946+
ttm_resource_cursor_fini(&curs->res_curs);
947+
spin_unlock(lru_lock);
948+
}
949+
EXPORT_SYMBOL(ttm_bo_lru_cursor_fini);
950+
951+
/**
952+
* ttm_bo_lru_cursor_init() - Initialize a struct ttm_bo_lru_cursor
953+
* @curs: The ttm_bo_lru_cursor to initialize.
954+
* @man: The ttm resource_manager whose LRU lists to iterate over.
955+
* @ctx: The ttm_operation_ctx to govern the locking.
956+
*
957+
* Initialize a struct ttm_bo_lru_cursor. Currently only trylocking
958+
* or prelocked buffer objects are available as detailed by
959+
* @ctx::resv and @ctx::allow_res_evict. Ticketlocking is not
960+
* supported.
961+
*
962+
* Return: Pointer to @curs. The function does not fail.
963+
*/
964+
struct ttm_bo_lru_cursor *
965+
ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs,
966+
struct ttm_resource_manager *man,
967+
struct ttm_operation_ctx *ctx)
968+
{
969+
memset(curs, 0, sizeof(*curs));
970+
ttm_resource_cursor_init(&curs->res_curs, man);
971+
curs->ctx = ctx;
972+
973+
return curs;
974+
}
975+
EXPORT_SYMBOL(ttm_bo_lru_cursor_init);
976+
977+
static struct ttm_buffer_object *
978+
ttm_bo_from_res_reserved(struct ttm_resource *res, struct ttm_bo_lru_cursor *curs)
979+
{
980+
struct ttm_buffer_object *bo = res->bo;
981+
982+
if (!ttm_lru_walk_trylock(curs->ctx, bo, &curs->needs_unlock))
983+
return NULL;
984+
985+
if (!ttm_bo_get_unless_zero(bo)) {
986+
if (curs->needs_unlock)
987+
dma_resv_unlock(bo->base.resv);
988+
return NULL;
989+
}
990+
991+
curs->bo = bo;
992+
return bo;
993+
}
994+
995+
/**
996+
* ttm_bo_lru_cursor_next() - Continue iterating a manager's LRU lists
997+
* to find and lock buffer object.
998+
* @curs: The cursor initialized using ttm_bo_lru_cursor_init() and
999+
* ttm_bo_lru_cursor_first().
1000+
*
1001+
* Return: A pointer to a locked and reference-counted buffer object,
1002+
* or NULL if none could be found and looping should be terminated.
1003+
*/
1004+
struct ttm_buffer_object *ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs)
1005+
{
1006+
spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock;
1007+
struct ttm_resource *res = NULL;
1008+
struct ttm_buffer_object *bo;
1009+
1010+
ttm_bo_lru_cursor_cleanup_bo(curs);
1011+
1012+
spin_lock(lru_lock);
1013+
for (;;) {
1014+
res = ttm_resource_manager_next(&curs->res_curs);
1015+
if (!res)
1016+
break;
1017+
1018+
bo = ttm_bo_from_res_reserved(res, curs);
1019+
if (bo)
1020+
break;
1021+
}
1022+
1023+
spin_unlock(lru_lock);
1024+
return res ? bo : NULL;
1025+
}
1026+
EXPORT_SYMBOL(ttm_bo_lru_cursor_next);
1027+
1028+
/**
1029+
* ttm_bo_lru_cursor_first() - Start iterating a manager's LRU lists
1030+
* to find and lock buffer object.
1031+
* @curs: The cursor initialized using ttm_bo_lru_cursor_init().
1032+
*
1033+
* Return: A pointer to a locked and reference-counted buffer object,
1034+
* or NULL if none could be found and looping should be terminated.
1035+
*/
1036+
struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs)
1037+
{
1038+
spinlock_t *lru_lock = &curs->res_curs.man->bdev->lru_lock;
1039+
struct ttm_buffer_object *bo;
1040+
struct ttm_resource *res;
1041+
1042+
spin_lock(lru_lock);
1043+
res = ttm_resource_manager_first(&curs->res_curs);
1044+
if (!res) {
1045+
spin_unlock(lru_lock);
1046+
return NULL;
1047+
}
1048+
1049+
bo = ttm_bo_from_res_reserved(res, curs);
1050+
spin_unlock(lru_lock);
1051+
1052+
return bo ? bo : ttm_bo_lru_cursor_next(curs);
1053+
}
1054+
EXPORT_SYMBOL(ttm_bo_lru_cursor_first);

include/drm/ttm/ttm_bo.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,4 +467,76 @@ void ttm_bo_tt_destroy(struct ttm_buffer_object *bo);
467467
int ttm_bo_populate(struct ttm_buffer_object *bo,
468468
struct ttm_operation_ctx *ctx);
469469

470+
/* Driver LRU walk helpers initially targeted for shrinking. */
471+
472+
/**
473+
* struct ttm_bo_lru_cursor - Iterator cursor for TTM LRU list looping
474+
*/
475+
struct ttm_bo_lru_cursor {
476+
/** @res_curs: Embedded struct ttm_resource_cursor. */
477+
struct ttm_resource_cursor res_curs;
478+
/**
479+
* @ctx: The struct ttm_operation_ctx used while looping.
480+
* governs the locking mode.
481+
*/
482+
struct ttm_operation_ctx *ctx;
483+
/**
484+
* @bo: Buffer object pointer if a buffer object is refcounted,
485+
* NULL otherwise.
486+
*/
487+
struct ttm_buffer_object *bo;
488+
/**
489+
* @needs_unlock: Valid iff @bo != NULL. The bo resv needs
490+
* unlock before the next iteration or after loop exit.
491+
*/
492+
bool needs_unlock;
493+
};
494+
495+
void ttm_bo_lru_cursor_fini(struct ttm_bo_lru_cursor *curs);
496+
497+
struct ttm_bo_lru_cursor *
498+
ttm_bo_lru_cursor_init(struct ttm_bo_lru_cursor *curs,
499+
struct ttm_resource_manager *man,
500+
struct ttm_operation_ctx *ctx);
501+
502+
struct ttm_buffer_object *ttm_bo_lru_cursor_first(struct ttm_bo_lru_cursor *curs);
503+
504+
struct ttm_buffer_object *ttm_bo_lru_cursor_next(struct ttm_bo_lru_cursor *curs);
505+
506+
/*
507+
* Defines needed to use autocleanup (linux/cleanup.h) with struct ttm_bo_lru_cursor.
508+
*/
509+
DEFINE_CLASS(ttm_bo_lru_cursor, struct ttm_bo_lru_cursor *,
510+
if (_T) {ttm_bo_lru_cursor_fini(_T); },
511+
ttm_bo_lru_cursor_init(curs, man, ctx),
512+
struct ttm_bo_lru_cursor *curs, struct ttm_resource_manager *man,
513+
struct ttm_operation_ctx *ctx);
514+
static inline void *
515+
class_ttm_bo_lru_cursor_lock_ptr(class_ttm_bo_lru_cursor_t *_T)
516+
{ return *_T; }
517+
#define class_ttm_bo_lru_cursor_is_conditional false
518+
519+
/**
520+
* ttm_bo_lru_for_each_reserved_guarded() - Iterate over buffer objects owning
521+
* resources on LRU lists.
522+
* @_cursor: struct ttm_bo_lru_cursor to use for the iteration.
523+
* @_man: The resource manager whose LRU lists to iterate over.
524+
* @_ctx: The struct ttm_operation_context to govern the @_bo locking.
525+
* @_bo: The struct ttm_buffer_object pointer pointing to the buffer object
526+
* for the current iteration.
527+
*
528+
* Iterate over all resources of @_man and for each resource, attempt to
529+
* reference and lock (using the locking mode detailed in @_ctx) the buffer
530+
* object it points to. If successful, assign @_bo to the address of the
531+
* buffer object and update @_cursor. The iteration is guarded in the
532+
* sense that @_cursor will be initialized before looping start and cleaned
533+
* up at looping termination, even if terminated prematurely by, for
534+
* example a return or break statement. Exiting the loop will also unlock
535+
* (if needed) and unreference @_bo.
536+
*/
537+
#define ttm_bo_lru_for_each_reserved_guarded(_cursor, _man, _ctx, _bo) \
538+
scoped_guard(ttm_bo_lru_cursor, _cursor, _man, _ctx) \
539+
for ((_bo) = ttm_bo_lru_cursor_first(_cursor); (_bo); \
540+
(_bo) = ttm_bo_lru_cursor_next(_cursor))
541+
470542
#endif

0 commit comments

Comments
 (0)