On 2026-08-20 11:36, Sreekant Somasekharan wrote:
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.

This special handling of doorbells for oversubscribed SDMA queues is only needed if you use more queues than doorbells _in the same process_. Across multiple processes this is not needed, because each process gets a unique set of doorbells.

Is the goal of this change really to enable oversubscription of SDMA queue slots by a single process? Is that even useful? Do you have a use case for that?

Regards,
  Felix



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*/

Reply via email to