From: "Christian König" <christian.koenig@amd.com>
To: Pierre-Eric Pelloux-Prayer <pierre-eric@damsy.net>,
Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>,
Alex Deucher <alexander.deucher@amd.com>,
David Airlie <airlied@gmail.com>, Simona Vetter <simona@ffwll.ch>,
Huang Rui <ray.huang@amd.com>,
Matthew Auld <matthew.auld@intel.com>,
Matthew Brost <matthew.brost@intel.com>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>,
Sumit Semwal <sumit.semwal@linaro.org>
Cc: amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
linux-kernel@vger.kernel.org, linux-media@vger.kernel.org,
linaro-mm-sig@lists.linaro.org
Subject: Re: [PATCH v1 02/20] drm/ttm: rework pipelined eviction fence handling
Date: Wed, 5 Nov 2025 14:00:24 +0100 [thread overview]
Message-ID: <4c7011f0-5886-4e1e-a614-a6107d9b470c@amd.com> (raw)
In-Reply-To: <5bf372ea-40ef-4b07-be13-53451828d3e1@damsy.net>
On 11/5/25 11:34, Pierre-Eric Pelloux-Prayer wrote:
>>
>>> + } else {
>>> + all_signaled = false;
>>> + if (no_wait_gpu) {
>>> + spin_unlock(&man->pipelined_eviction.lock);
>>> + return -EBUSY;
>>> + }
>>> + fences_to_add[n++] = dma_fence_get(fence);
>>> + }
>>> + }
>>> + spin_unlock(&man->pipelined_eviction.lock);
>>> +
>>> + if (all_signaled)
>>> return 0;
>>> - if (no_wait_gpu) {
>>> - ret = dma_fence_is_signaled(fence) ? 0 : -EBUSY;
>>> - dma_fence_put(fence);
>>> - return ret;
>>> + for (i = 0; i < n; i++) {
>>> + dma_resv_add_fence(bo->base.resv, fences_to_add[i], DMA_RESV_USAGE_KERNEL);
>>> + dma_fence_put(fences_to_add[i]);
>>> }
>>> - dma_resv_add_fence(bo->base.resv, fence, DMA_RESV_USAGE_KERNEL);
>>> -
>>> - ret = dma_resv_reserve_fences(bo->base.resv, 1);
>>> - dma_fence_put(fence);
>>> - return ret;
>>> + return dma_resv_reserve_fences(bo->base.resv, TTM_FENCES_MAX_SLOT_COUNT);
>>
>> Please separate out a patch where the call to dma_resv_reserve_fences() is removed here.
>
> Can you remind me why it's not needed?
Some years ago the dma_resv object had a fixed field for an exclusive fence.
When we removed that we sprinkled calls like "dma_resv_reserve_fences(bo->base.resv, 1)" all over the place where we previously used this exclusive fence slot to prevent things from going boom!
It could be that some old drivers like radeon or qxl still rely on that somewhere, but that would then clearly be a driver bug.
What we could do is to either leave it alone or remove it, but changing it to reserving TTM_FENCES_MAX_SLOT_COUNT is clearly not correct.
>>
>>> }
>>> /**
>>> @@ -718,7 +732,7 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
>>> int i, ret;
>>> ticket = dma_resv_locking_ctx(bo->base.resv);
>>> - ret = dma_resv_reserve_fences(bo->base.resv, 1);
>>> + ret = dma_resv_reserve_fences(bo->base.resv, TTM_FENCES_MAX_SLOT_COUNT);
>>> if (unlikely(ret))
>>> return ret;
>>> @@ -757,7 +771,7 @@ static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
>>> return ret;
>>> }
>>> - ret = ttm_bo_add_move_fence(bo, man, ctx->no_wait_gpu);
>>> + ret = ttm_bo_add_pipelined_eviction_fences(bo, man, ctx->no_wait_gpu);
>>> if (unlikely(ret)) {
>>> ttm_resource_free(bo, res);
>>> if (ret == -EBUSY)
>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
>>> index acbbca9d5c92..ada8af965acf 100644
>>> --- a/drivers/gpu/drm/ttm/ttm_bo_util.c
>>> +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
>>> @@ -258,7 +258,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
>>> ret = dma_resv_trylock(&fbo->base.base._resv);
>>> WARN_ON(!ret);
>>> - ret = dma_resv_reserve_fences(&fbo->base.base._resv, 1);
>>> + ret = dma_resv_reserve_fences(&fbo->base.base._resv, TTM_FENCES_MAX_SLOT_COUNT);
>>> if (ret) {
>>> dma_resv_unlock(&fbo->base.base._resv);
>>> kfree(fbo);
>>> @@ -646,6 +646,8 @@ static void ttm_bo_move_pipeline_evict(struct ttm_buffer_object *bo,
>>> {
>>> struct ttm_device *bdev = bo->bdev;
>>> struct ttm_resource_manager *from;
>>> + struct dma_fence *tmp;
>>> + int i, free_slot = -1;
>>> from = ttm_manager_type(bdev, bo->resource->mem_type);
>>> @@ -653,13 +655,35 @@ static void ttm_bo_move_pipeline_evict(struct ttm_buffer_object *bo,
>>> * BO doesn't have a TTM we need to bind/unbind. Just remember
>>> * this eviction and free up the allocation
>>> */
>>> - spin_lock(&from->move_lock);
>>> - if (!from->move || dma_fence_is_later(fence, from->move)) {
>>> - dma_fence_put(from->move);
>>> - from->move = dma_fence_get(fence);
>>> + spin_lock(&from->pipelined_eviction.lock);
>>> + for (i = 0; i < from->pipelined_eviction.n_fences; i++) {
>>> + tmp = from->pipelined_eviction.fences[i];
>>> + if (!tmp) {
>>> + if (free_slot < 0)
>>> + free_slot = i;
>>> + continue;
>>
>> Just break here.
>
> The logic here is to reuse context slots. Even if slot 0 is empty, I need to use slot 1 if slot 1's context is the same as fence->context.
Good point, but slot 0 should never be empty. See we fill the slots starting from 0 and then incrementing you either have NULL or a slot which doesn't match.
> This way, we're guaranteed to find a slot for all contexts used by the driver.
>
>>
>>> + }
>>> + if (fence->context != tmp->context)
>>> + continue;
>>> + if (dma_fence_is_later(fence, tmp)) {
>>> + dma_fence_put(tmp);
>>> + free_slot = i;
>>> + break;
>>> + }
>>> + goto unlock;
>>> + }
>>> + if (free_slot >= 0) {
>>
>> Drop free_slot and check i here.
>>
>>> + from->pipelined_eviction.fences[free_slot] = dma_fence_get(fence);
>>> + } else {
>>> + WARN(1, "not enough fence slots for all fence contexts");
>>> + spin_unlock(&from->pipelined_eviction.lock);
>>> + dma_fence_wait(fence, false);
>>> + goto end;
>>> }
>>> - spin_unlock(&from->move_lock);
>>> +unlock:
>>> + spin_unlock(&from->pipelined_eviction.lock);
>>> +end:
>>> ttm_resource_free(bo, &bo->resource);
>>> }
>>> diff --git a/drivers/gpu/drm/ttm/ttm_resource.c b/drivers/gpu/drm/ttm/ttm_resource.c
>>> index e2c82ad07eb4..ae0d4621cc55 100644
>>> --- a/drivers/gpu/drm/ttm/ttm_resource.c
>>> +++ b/drivers/gpu/drm/ttm/ttm_resource.c
>>> @@ -523,14 +523,19 @@ void ttm_resource_manager_init(struct ttm_resource_manager *man,
>>> {
>>> unsigned i;
>>> - spin_lock_init(&man->move_lock);
>>> man->bdev = bdev;
>>> man->size = size;
>>> man->usage = 0;
>>> for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
>>> INIT_LIST_HEAD(&man->lru[i]);
>>> - man->move = NULL;
>>> + spin_lock_init(&man->pipelined_eviction.lock);
>>> + for (i = 0; i < TTM_FENCES_MAX_SLOT_COUNT; i++)
>>> + man->pipelined_eviction.fences[i] = NULL;
>>> + /* Can be overridden by drivers that wants to use more than 1 entity
>>> + * for moves and evictions (limited to TTM_FENCES_MAX_SLOT_COUNT).
>>> + */
>>> + man->pipelined_eviction.n_fences = 1;
>>> }
>>> EXPORT_SYMBOL(ttm_resource_manager_init);
>>> @@ -551,7 +556,7 @@ int ttm_resource_manager_evict_all(struct ttm_device *bdev,
>>> .no_wait_gpu = false,
>>> };
>>> struct dma_fence *fence;
>>> - int ret;
>>> + int ret, i;
>>> do {
>>> ret = ttm_bo_evict_first(bdev, man, &ctx);
>>> @@ -561,18 +566,32 @@ int ttm_resource_manager_evict_all(struct ttm_device *bdev,
>>> if (ret && ret != -ENOENT)
>>> return ret;
>>> - spin_lock(&man->move_lock);
>>> - fence = dma_fence_get(man->move);
>>> - spin_unlock(&man->move_lock);
>>> + ret = 0;
>>> - if (fence) {
>>> - ret = dma_fence_wait(fence, false);
>>> - dma_fence_put(fence);
>>> - if (ret)
>>> - return ret;
>>> - }
>>> + do {
>>> + fence = NULL;
>>> - return 0;
>>> + spin_lock(&man->pipelined_eviction.lock);
>>> + for (i = 0; i < man->pipelined_eviction.n_fences; i++) {
>>> + fence = man->pipelined_eviction.fences[i];
>>
>>> + man->pipelined_eviction.fences[i] = NULL;
>>
>> Drop that. We should never set man->pipelined_eviction.fences to NULL.
>
> Why?
To simplify the logic while filling the slots.
dma_fences are made to be keept around for long.
>>
>>> +
>>> /**
>>> * enum ttm_lru_item_type - enumerate ttm_lru_item subclasses
>>> */
>>> @@ -180,8 +189,10 @@ struct ttm_resource_manager_func {
>>> * @size: Size of the managed region.
>>> * @bdev: ttm device this manager belongs to
>>> * @func: structure pointer implementing the range manager. See above
>>> - * @move_lock: lock for move fence
>>> - * @move: The fence of the last pipelined move operation.
>>> + * @pipelined_eviction.lock: lock for eviction fences
>>> + * @pipelined_eviction.n_fences: The number of fences allowed in the array. If
>>> + * 0, pipelined evictions aren't used.
>>> + * @pipelined_eviction.fences: The fences of the last pipelined move operation.
>>> * @lru: The lru list for this memory type.
>>> *
>>> * This structure is used to identify and manage memory types for a device.
>>> @@ -195,12 +206,15 @@ struct ttm_resource_manager {
>>> struct ttm_device *bdev;
>>> uint64_t size;
>>> const struct ttm_resource_manager_func *func;
>>> - spinlock_t move_lock;
>>> - /*
>>> - * Protected by @move_lock.
>>> + /* This is very similar to a dma_resv object, but locking rules make
>>> + * it difficult to use a it in this context.
>>> */
>>> - struct dma_fence *move;
>>> + struct {
>>> + spinlock_t lock;
>>> + int n_fences;
>>> + struct dma_fence *fences[TTM_FENCES_MAX_SLOT_COUNT];
>>> + } pipelined_eviction;
>>
>> Drop the separate structure, just make move an array instead.
>
> IMO pipelined_eviction.fences and pipelined_eviction.lock is clearer when reading the code than moves and move_lock but if you prefer I'll switch back to the old names.
The name "pipelined_eviction" is just a bit to long. Maybe just eviction_fences and eviction_fences_lock?
Regards,
Christian.
>>
>> And also drop n_fences. Just always take a look at all fences.
>
> OK.
>
> Thanks,
> Pierre-Eric
>
>>
>> Regards,
>> Christian.
>>
>>> /*
>>> * Protected by the bdev->lru_lock.
>>> @@ -421,8 +435,12 @@ static inline bool ttm_resource_manager_used(struct ttm_resource_manager *man)
>>> static inline void
>>> ttm_resource_manager_cleanup(struct ttm_resource_manager *man)
>>> {
>>> - dma_fence_put(man->move);
>>> - man->move = NULL;
>>> + int i;
>>> +
>>> + for (i = 0; i < TTM_FENCES_MAX_SLOT_COUNT; i++) {
>>> + dma_fence_put(man->pipelined_eviction.fences[i]);
>>> + man->pipelined_eviction.fences[i] = NULL;
>>> + }
>>> }
>>> void ttm_lru_bulk_move_init(struct ttm_lru_bulk_move *bulk);
next prev parent reply other threads:[~2025-11-05 13:00 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-04 8:35 [PATCH v1 00/20] drm/amdgpu: use all SDMA instances for TTM clears and moves Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 01/20] drm/amdgpu: give each kernel job a unique id Pierre-Eric Pelloux-Prayer
2025-11-04 13:58 ` Christian König
2025-11-04 8:35 ` [PATCH v1 02/20] drm/ttm: rework pipelined eviction fence handling Pierre-Eric Pelloux-Prayer
2025-11-04 14:12 ` Christian König
2025-11-05 10:34 ` Pierre-Eric Pelloux-Prayer
2025-11-05 13:00 ` Christian König [this message]
2025-11-04 8:35 ` [PATCH v1 03/20] drm/amdgpu: remove direct_submit arg from amdgpu_copy_buffer Pierre-Eric Pelloux-Prayer
2025-11-04 14:13 ` Christian König
2025-11-04 8:35 ` [PATCH v1 04/20] drm/amdgpu: introduce amdgpu_ttm_entity Pierre-Eric Pelloux-Prayer
2025-11-04 15:13 ` Christian König
2025-11-04 8:35 ` [PATCH v1 05/20] drm/amdgpu: pass the entity to use to ttm functions Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 06/20] drm/amdgpu: statically assign gart windows to ttm entities Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 07/20] drm/amdgpu: allocate multiple clear entities Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 08/20] drm/amdgpu: allocate multiple move entities Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 09/20] drm/amdgpu: pass optional dependency to amdgpu_fill_buffer Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 10/20] drm/amdgpu: prepare amdgpu_fill_buffer to use N entities Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 11/20] drm/amdgpu: use multiple entities in amdgpu_fill_buffer Pierre-Eric Pelloux-Prayer
2025-11-04 16:40 ` Christian König
2025-11-05 10:39 ` Pierre-Eric Pelloux-Prayer
2025-11-05 13:03 ` Christian König
2025-11-12 10:39 ` Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 12/20] drm/amdgpu: use TTM_FENCES_MAX_SLOT_COUNT Pierre-Eric Pelloux-Prayer
2025-11-05 8:36 ` Christian König
2025-11-04 8:35 ` [PATCH v1 13/20] drm/amdgpu: use multiple entities in amdgpu_move_blit Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 14/20] drm/amdgpu: pass all the sdma rings to amdgpu_mman Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 15/20] drm/amdgpu: introduce amdgpu_sdma_set_vm_pte_scheds Pierre-Eric Pelloux-Prayer
2025-11-05 8:41 ` Christian König
2025-11-04 8:35 ` [PATCH v1 16/20] drm/amdgpu: give ttm entities access to all the sdma scheds Pierre-Eric Pelloux-Prayer
2025-11-05 8:45 ` Christian König
2025-11-05 10:17 ` Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 17/20] drm/amdgpu: get rid of amdgpu_ttm_clear_buffer Pierre-Eric Pelloux-Prayer
2025-11-05 8:46 ` Christian König
2025-11-05 9:30 ` Pierre-Eric Pelloux-Prayer
2025-11-05 10:07 ` Christian König
2025-11-04 8:35 ` [PATCH v1 18/20] drm/amdgpu: rename amdgpu_fill_buffer as amdgpu_clear_buffer Pierre-Eric Pelloux-Prayer
2025-11-05 8:47 ` Christian König
2025-11-04 8:35 ` [PATCH v1 19/20] drm/amdgpu: use larger gart window when possible Pierre-Eric Pelloux-Prayer
2025-11-04 8:35 ` [PATCH v1 20/20] drm/amdgpu: double AMDGPU_GTT_MAX_TRANSFER_SIZE Pierre-Eric Pelloux-Prayer
2025-11-04 13:56 ` Christian König
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4c7011f0-5886-4e1e-a614-a6107d9b470c@amd.com \
--to=christian.koenig@amd.com \
--cc=airlied@gmail.com \
--cc=alexander.deucher@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=matthew.auld@intel.com \
--cc=matthew.brost@intel.com \
--cc=mripard@kernel.org \
--cc=pierre-eric.pelloux-prayer@amd.com \
--cc=pierre-eric@damsy.net \
--cc=ray.huang@amd.com \
--cc=simona@ffwll.ch \
--cc=sumit.semwal@linaro.org \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®