This patch adds basic eviction fence framework for the gfx buffers. The idea is to: - One eviction fence is created per gfx process, at kms_open. - This same fence is attached to all the gem buffers created by this process. This framework will be further used for usermode queues. V2: Addressed review comments from Christian - keep fence_ctx and fence_seq directly in fpriv - evcition_fence should be dynamically allocated - do not save eviction fence instance in BO, there could be many such fences attached to one BO - use dma_resv_replace_fence() in detach Cc: Christian Koenig <christian.koenig@xxxxxxx> Cc: Alex Deucher <alexander.deucher@xxxxxxx> Signed-off-by: Shashank Sharma <shashank.sharma@xxxxxxx> --- drivers/gpu/drm/amd/amdgpu/Makefile | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 20 ++++ .../drm/amd/amdgpu/amdgpu_eviction_fence.c | 106 ++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 10 +- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 8 +- 5 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index b0103f404957..9743bf06d6aa 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -82,7 +82,7 @@ amdgpu-y += amdgpu_device.o amdgpu_doorbell_mgr.o amdgpu_kms.o \ amdgpu_fw_attestation.o amdgpu_securedisplay.o \ amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o \ amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_aca.o \ - amdgpu_userq_fence.o + amdgpu_userq_fence.o amdgpu_eviction_fence.o amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 2d5ef2e74c71..a37193fc9ddc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -465,6 +465,11 @@ struct amdgpu_flip_work { bool async; }; +struct amdgpu_eviction_fence { + struct dma_fence base; + spinlock_t lock; + char timeline_name[TASK_COMM_LEN]; +}; /* * file private structure @@ -479,6 +484,12 @@ struct amdgpu_fpriv { struct idr bo_list_handles; struct amdgpu_ctx_mgr ctx_mgr; struct amdgpu_userq_mgr userq_mgr; + + /* Eviction fence infra */ + u64 ev_fence_ctx; + atomic_t ev_fence_seq; + struct amdgpu_eviction_fence *ev_fence; + /** GPU partition selection */ uint32_t xcp_id; }; @@ -1480,6 +1491,15 @@ void amdgpu_disable_vblank_kms(struct drm_crtc *crtc); int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +/* Eviction fence */ +struct amdgpu_eviction_fence *amdgpu_eviction_fence_create(struct amdgpu_fpriv *fpriv); +void amdgpu_eviction_fence_destroy(struct amdgpu_fpriv *fpriv); +int amdgpu_eviction_fence_attach(struct amdgpu_eviction_fence *ev_fence, + struct amdgpu_bo *bo); +void amdgpu_eviction_fence_detach(struct amdgpu_fpriv *fpriv, + struct amdgpu_eviction_fence *ev_fence, + struct amdgpu_bo *bo); + /* * functions used by amdgpu_encoder.c */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c new file mode 100644 index 000000000000..1a03f040ccc8 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2024 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include <linux/sched.h> +#include "amdgpu.h" + +static const char * +amdgpu_ev_fence_get_driver_name(struct dma_fence *fence) +{ + return "amdgpu"; +} + +static const char * +amdgpu_ev_fence_get_timeline_name(struct dma_fence *f) +{ + struct amdgpu_eviction_fence *ef; + + ef = container_of(f, struct amdgpu_eviction_fence, base); + return ef->timeline_name; +} + +static const struct dma_fence_ops amdgpu_eviction_fence_ops = { + .use_64bit_seqno = true, + .get_driver_name = amdgpu_ev_fence_get_driver_name, + .get_timeline_name = amdgpu_ev_fence_get_timeline_name, +}; + +struct amdgpu_eviction_fence * +amdgpu_eviction_fence_create(struct amdgpu_fpriv *fpriv) +{ + struct amdgpu_eviction_fence *ev_fence; + atomic_t seq = ATOMIC_INIT(0); + + ev_fence = kzalloc(sizeof(*ev_fence), GFP_KERNEL); + if (!ev_fence) + return NULL; + + spin_lock_init(&ev_fence->lock); + fpriv->ev_fence_seq = seq; + fpriv->ev_fence_ctx = dma_fence_context_alloc(1); + dma_fence_init(&ev_fence->base, &amdgpu_eviction_fence_ops, + &ev_fence->lock, fpriv->ev_fence_ctx, + atomic_inc_return(&fpriv->ev_fence_seq)); + + return ev_fence; +} + +void amdgpu_eviction_fence_destroy(struct amdgpu_fpriv *fpriv) +{ + kfree(fpriv->ev_fence); +} + +int amdgpu_eviction_fence_attach(struct amdgpu_eviction_fence *ev_fence, + struct amdgpu_bo *bo) +{ + struct dma_fence *ef = &ev_fence->base; + struct dma_resv *resv = bo->tbo.base.resv; + int ret; + + ret = dma_resv_reserve_fences(resv, 1); + if (ret) { + dma_fence_wait(ef, false); + return ret; + } + + dma_resv_add_fence(resv, ef, DMA_RESV_USAGE_BOOKKEEP); + dma_fence_get(ef); + return 0; +} + +void amdgpu_eviction_fence_detach(struct amdgpu_fpriv *fpriv, + struct amdgpu_eviction_fence *ev_fence, + struct amdgpu_bo *bo) +{ + struct dma_fence *stub; + struct dma_fence *ef = &ev_fence->base; + + stub = dma_fence_get_stub(); + dma_resv_replace_fences(bo->tbo.base.resv, fpriv->ev_fence_ctx, + stub, DMA_RESV_USAGE_BOOKKEEP); + + if (!dma_fence_is_signaled(ef)) + dma_fence_put(ef); + dma_fence_put(stub); +} + diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 85f1c05890bb..3355b750a652 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -199,8 +199,14 @@ static int amdgpu_gem_object_open(struct drm_gem_object *obj, * but not for export, this is a different lock class that cannot lead to * circular lock dependencies. */ - if (!vm->is_compute_context || !vm->process_info) + if (!vm->is_compute_context || !vm->process_info) { + /* attach gfx eviction fence */ + if (amdgpu_eviction_fence_attach(fpriv->ev_fence, abo)) + DRM_DEBUG_DRIVER("Failed to attach eviction fence to BO\n"); + return 0; + } + if (!obj->import_attach || !dma_buf_is_dynamic(obj->import_attach->dmabuf)) return 0; @@ -236,6 +242,8 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, struct drm_exec exec; long r; + amdgpu_eviction_fence_detach(fpriv, fpriv->ev_fence, bo); + drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_prepare_obj(&exec, &bo->tbo.base, 1); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index d78b06af834e..9f4ffd195fea 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1294,7 +1294,6 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return 0; } - /* * Outdated mess for old drm with Xorg being in charge (void function now). */ @@ -1387,6 +1386,12 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) mutex_init(&fpriv->bo_list_lock); idr_init_base(&fpriv->bo_list_handles, 1); + fpriv->ev_fence = amdgpu_eviction_fence_create(fpriv); + if (!fpriv->ev_fence) { + DRM_ERROR("Failed to craete eviction fence\n"); + goto error_vm; + } + amdgpu_ctx_mgr_init(&fpriv->ctx_mgr, adev); r = amdgpu_userq_mgr_init(&fpriv->userq_mgr, adev); @@ -1460,6 +1465,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_bo_unreserve(pd); } + amdgpu_eviction_fence_destroy(fpriv); amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr); amdgpu_vm_fini(adev, &fpriv->vm); amdgpu_userq_mgr_fini(&fpriv->userq_mgr); -- 2.43.2