150 lines
5.1 KiB
Diff
150 lines
5.1 KiB
Diff
From a166b1f311da3d34e068ece6452a7241f8ab421d Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
|
|
Date: Wed, 29 Oct 2025 15:36:32 +0100
|
|
Subject: [PATCH] drm/amdgpu: avoid memory allocation in the critical code path
|
|
v3
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
When we run out of VMIDs we need to wait for some to become available.
|
|
Previously we were using a dma_fence_array for that, but this means that
|
|
we have to allocate memory.
|
|
|
|
Instead just wait for the first not signaled fence from the least recently
|
|
used VMID to signal. That is not as efficient since we end up in this
|
|
function multiple times again, but allocating memory can easily fail or
|
|
deadlock if we have to wait for memory to become available.
|
|
|
|
v2: remove now unused VM manager fields
|
|
v3: fix dma_fence reference
|
|
|
|
Signed-off-by: Christian König <christian.koenig@amd.com>
|
|
Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4258
|
|
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
|
|
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
|
|
Cherry-picked-for: https://gitlab.archlinux.org/archlinux/packaging/packages/linux/-/issues/164
|
|
---
|
|
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 52 +++++++------------------
|
|
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 7 ----
|
|
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h | 4 --
|
|
3 files changed, 14 insertions(+), 49 deletions(-)
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
|
|
index 3ef5bc95642cab..b2af2cc6826c44 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
|
|
@@ -201,58 +201,34 @@ static int amdgpu_vmid_grab_idle(struct amdgpu_ring *ring,
|
|
struct amdgpu_device *adev = ring->adev;
|
|
unsigned vmhub = ring->vm_hub;
|
|
struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
|
|
- struct dma_fence **fences;
|
|
- unsigned i;
|
|
|
|
+ /* If anybody is waiting for a VMID let everybody wait for fairness */
|
|
if (!dma_fence_is_signaled(ring->vmid_wait)) {
|
|
*fence = dma_fence_get(ring->vmid_wait);
|
|
return 0;
|
|
}
|
|
|
|
- fences = kmalloc_array(id_mgr->num_ids, sizeof(void *), GFP_NOWAIT);
|
|
- if (!fences)
|
|
- return -ENOMEM;
|
|
-
|
|
/* Check if we have an idle VMID */
|
|
- i = 0;
|
|
- list_for_each_entry((*idle), &id_mgr->ids_lru, list) {
|
|
+ list_for_each_entry_reverse((*idle), &id_mgr->ids_lru, list) {
|
|
/* Don't use per engine and per process VMID at the same time */
|
|
struct amdgpu_ring *r = adev->vm_manager.concurrent_flush ?
|
|
NULL : ring;
|
|
|
|
- fences[i] = amdgpu_sync_peek_fence(&(*idle)->active, r);
|
|
- if (!fences[i])
|
|
- break;
|
|
- ++i;
|
|
+ *fence = amdgpu_sync_peek_fence(&(*idle)->active, r);
|
|
+ if (!(*fence))
|
|
+ return 0;
|
|
}
|
|
|
|
- /* If we can't find a idle VMID to use, wait till one becomes available */
|
|
- if (&(*idle)->list == &id_mgr->ids_lru) {
|
|
- u64 fence_context = adev->vm_manager.fence_context + ring->idx;
|
|
- unsigned seqno = ++adev->vm_manager.seqno[ring->idx];
|
|
- struct dma_fence_array *array;
|
|
- unsigned j;
|
|
-
|
|
- *idle = NULL;
|
|
- for (j = 0; j < i; ++j)
|
|
- dma_fence_get(fences[j]);
|
|
-
|
|
- array = dma_fence_array_create(i, fences, fence_context,
|
|
- seqno, true);
|
|
- if (!array) {
|
|
- for (j = 0; j < i; ++j)
|
|
- dma_fence_put(fences[j]);
|
|
- kfree(fences);
|
|
- return -ENOMEM;
|
|
- }
|
|
-
|
|
- *fence = dma_fence_get(&array->base);
|
|
- dma_fence_put(ring->vmid_wait);
|
|
- ring->vmid_wait = &array->base;
|
|
- return 0;
|
|
- }
|
|
- kfree(fences);
|
|
+ /*
|
|
+ * If we can't find a idle VMID to use, wait on a fence from the least
|
|
+ * recently used in the hope that it will be available soon.
|
|
+ */
|
|
+ *idle = NULL;
|
|
+ dma_fence_put(ring->vmid_wait);
|
|
+ ring->vmid_wait = dma_fence_get(*fence);
|
|
|
|
+ /* This is the reference we return */
|
|
+ dma_fence_get(*fence);
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
|
|
index 3d2f9d0e2d2397..63e49577a5b2e4 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
|
|
@@ -2830,8 +2830,6 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
|
|
*/
|
|
void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
|
{
|
|
- unsigned i;
|
|
-
|
|
/* Concurrent flushes are only possible starting with Vega10 and
|
|
* are broken on Navi10 and Navi14.
|
|
*/
|
|
@@ -2840,11 +2838,6 @@ void amdgpu_vm_manager_init(struct amdgpu_device *adev)
|
|
adev->asic_type == CHIP_NAVI14);
|
|
amdgpu_vmid_mgr_init(adev);
|
|
|
|
- adev->vm_manager.fence_context =
|
|
- dma_fence_context_alloc(AMDGPU_MAX_RINGS);
|
|
- for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
|
|
- adev->vm_manager.seqno[i] = 0;
|
|
-
|
|
spin_lock_init(&adev->vm_manager.prt_lock);
|
|
atomic_set(&adev->vm_manager.num_prt_users, 0);
|
|
|
|
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
|
|
index cf0ec94e8a0754..15d757c016cbbc 100644
|
|
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
|
|
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
|
|
@@ -453,10 +453,6 @@ struct amdgpu_vm_manager {
|
|
unsigned int first_kfd_vmid;
|
|
bool concurrent_flush;
|
|
|
|
- /* Handling of VM fences */
|
|
- u64 fence_context;
|
|
- unsigned seqno[AMDGPU_MAX_RINGS];
|
|
-
|
|
uint64_t max_pfn;
|
|
uint32_t num_level;
|
|
uint32_t block_size;
|