[PATCH] drm/amdkfd: Enable SDMA queue oversubscription for GFX 12.0.x
Sreekant Somasekharan <[email protected]>
| Newsgroups | org.freedesktop.lists.amd-gfx |
|---|---|
| Message-ID | <[email protected]> |
When all HW SDMA slots are exhausted on GFX 12.0.x with MES enabled, allow new queues to reuse HW queue IDs round-robin via a dedicated monotonic rotor. Each oversubscribed queue gets a unique doorbell from the per-process bitmap pool so MES can multiplex them independently. Normal SDMA queues and all other GPU generations are unaffected. Assisted-by: Claude:Sonnet 4.6 Signed-off-by: Sreekant Somasekharan <[email protected]> --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 54 +++++++++++++++---- .../drm/amd/amdkfd/kfd_device_queue_manager.h | 4 ++ drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 1 + 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index a23384571193..10a672b87ca5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -556,8 +556,9 @@ static int allocate_doorbell(struct qcm_process_device *qpd, return -EINVAL; q->doorbell_id = q->properties.queue_id; - } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA || - q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) { + } else if ((q->properties.type == KFD_QUEUE_TYPE_SDMA || + q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) && + !q->properties.is_oversubscribed) { /* For SDMA queues on SOC15 with 8-byte doorbell, use static * doorbell assignments based on the engine and queue id. * The doobell index distance between RLC (2*i) and (2*i+1) @@ -583,7 +584,10 @@ static int allocate_doorbell(struct qcm_process_device *qpd, return -EINVAL; q->doorbell_id = valid_id; } else { - /* For CP queues on SOC15 */ + /* For CP queues on SOC15, and oversubscribed SDMA queues which + * reuse HW queue ids and so need a unique doorbell allocated + * from the per-process bitmap pool. + */ if (restore_id) { if (*restore_id >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) return -EINVAL; @@ -621,9 +625,14 @@ static void deallocate_doorbell(struct qcm_process_device *qpd, unsigned int old; struct kfd_node *dev = qpd->dqm->dev; + /* Oversubscribed SDMA queues allocate a doorbell from the bitmap pool + * (like CP queues), so they must be freed; normal SDMA queues use + * static doorbell assignments and must not be. + */ if (!KFD_IS_SOC15(dev) || - q->properties.type == KFD_QUEUE_TYPE_SDMA || - q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) + ((q->properties.type == KFD_QUEUE_TYPE_SDMA || + q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) && + !q->properties.is_oversubscribed)) return; old = test_and_clear_bit(q->doorbell_id, qpd->doorbell_bitmap); @@ -1800,15 +1809,33 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm, { struct device *dev = dqm->dev->adev->dev; int bit; + bool is_oversubscribed = false; if (q->properties.type == KFD_QUEUE_TYPE_SDMA) { if (bitmap_empty(dqm->sdma_bitmap, get_num_sdma_queues(dqm))) { - dev_warn(dev, "No more SDMA queue to allocate (%d total queues)\n", - get_num_sdma_queues(dqm)); - return -ENOMEM; - } + /* All HW queues are busy. On GFX 12.0.x under MES, + * oversubscribe by reusing a HW queue id round-robin; + * MES multiplexes the SW queues via their unique + * doorbells. The non-MES HWS runlist path cannot express + * duplicate sdma_ids, so it still fails with -ENOMEM. + */ + unsigned int num_reserved, num_available; + + if (KFD_GC_VERSION(dqm->dev) < IP_VERSION(12, 0, 0) || + KFD_GC_VERSION(dqm->dev) >= IP_VERSION(12, 1, 0) || + !dqm->dev->kfd->shared_resources.enable_mes) { + dev_warn(dev, "No more SDMA queue to allocate (%d total queues)\n", + get_num_sdma_queues(dqm)); + return -ENOMEM; + } - if (restore_sdma_id) { + num_reserved = kfd_get_num_sdma_engines(dqm->dev) * + dqm->dev->kfd->device_info.num_reserved_sdma_queues_per_engine; + num_available = get_num_sdma_queues(dqm) - num_reserved; + q->sdma_id = num_reserved + + dqm->sdma_oversub_rotor++ % num_available; + is_oversubscribed = true; + } else if (restore_sdma_id) { if (*restore_sdma_id >= get_num_sdma_queues(dqm)) return -EINVAL; @@ -1901,6 +1928,7 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm, return -ENOMEM; } } + q->properties.is_oversubscribed = is_oversubscribed; pr_debug("SDMA engine id: %d\n", q->properties.sdma_engine_id); pr_debug("SDMA queue id: %d\n", q->properties.sdma_queue_id); @@ -1914,7 +1942,11 @@ static void deallocate_sdma_queue(struct device_queue_manager *dqm, if (q->properties.type == KFD_QUEUE_TYPE_SDMA) { if (q->sdma_id >= get_num_sdma_queues(dqm)) return; - set_bit(q->sdma_id, dqm->sdma_bitmap); + /* Don't return oversubscribed queue IDs to bitmap. + * They are shared by multiple queues and managed via round-robin. + */ + if (!q->properties.is_oversubscribed) + set_bit(q->sdma_id, dqm->sdma_bitmap); } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI) { if (q->sdma_id >= get_num_xgmi_sdma_queues(dqm)) return; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index c9f9f7a87111..81626e657055 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -255,6 +255,10 @@ struct device_queue_manager { unsigned int gws_queue_count; unsigned int total_queue_count; unsigned int next_pipe_to_allocate; + /* Monotonically increasing counter used to round-robin oversubscribed + * SDMA queues across the available HW queue slots. + */ + unsigned int sdma_oversub_rotor; unsigned int *allocated_queues; DECLARE_BITMAP(sdma_bitmap, KFD_MAX_SDMA_QUEUES); DECLARE_BITMAP(xgmi_sdma_bitmap, KFD_MAX_SDMA_QUEUES); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index d8631847f0eb..5fff5e55fb09 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -531,6 +531,7 @@ struct queue_properties { bool is_dbg_wa; bool is_user_cu_masked; bool is_reset; + bool is_oversubscribed; /* Not relevant for user mode queues in cp scheduling */ unsigned int vmid; /* Relevant only for sdma queues*/ -- 2.43.0