Reading the KFD HQD debugfs node (dqm_debugfs_hqds) on a gc_12_1_0 part
oopses with a NULL pointer dereference:

  BUG: kernel NULL pointer dereference, address: 0000000000000000
  RIP: hqd_sdma_dump_v12_1+0x6a [amdgpu]
  Call Trace:
   dqm_debugfs_hqds+0x2da/0x360 [amdgpu]
   kfd_debugfs_hqds_by_device+0x74/0xa0 [amdgpu]
   seq_read ... __x64_sys_read

get_sdma_rlc_reg_offset() assumes an interleaved layout where the second
SDMA per XCC lives in a separate SDMA1_HWIP register aperture. On
gc_12_1_0 that aperture does not exist.

Rewrite get_sdma_rlc_reg_offset() to mirror sdma_v7_1_get_reg_offset():
base the offset on adev->reg_offset[GC_HWIP][xcc_id][0] and add the
per-instance SDMA1 offset for the odd instance.

Signed-off-by: Harish Kasiviswanathan <[email protected]>
Reviewed-by: Mukul Joshi <[email protected]>
---
 .../drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c  | 44 +++++++++++--------
 .../drm/amd/amdkfd/kfd_device_queue_manager.c |  9 ++++
 2 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
index bda9578c4035..ec095003667f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v12_1.c
@@ -77,25 +77,21 @@ static uint32_t get_sdma_rlc_reg_offset(struct 
amdgpu_device *adev,
                                unsigned int engine_id,
                                unsigned int queue_id)
 {
-       uint32_t sdma_engine_reg_base = 0;
-       uint32_t sdma_rlc_reg_offset;
        uint32_t dev_inst = GET_INST(SDMA0, engine_id);
+       int xcc_id = adev->sdma.instance[engine_id].xcc_id;
+       int xcc_inst = dev_inst % adev->sdma.num_inst_per_xcc;
+       uint32_t sdma_engine_reg_base;
+       uint32_t sdma_rlc_reg_offset;
 
-       switch (dev_inst % adev->sdma.num_inst_per_xcc) {
-       case 0:
-               sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA0,
-                               dev_inst / adev->sdma.num_inst_per_xcc,
-                               regSDMA0_SDMA_QUEUE0_RB_CNTL) - 
regSDMA0_SDMA_QUEUE0_RB_CNTL;
-               break;
-       case 1:
-               sdma_engine_reg_base = SOC15_REG_OFFSET(SDMA1,
-                               dev_inst / adev->sdma.num_inst_per_xcc,
-                               regSDMA1_SDMA_QUEUE0_RB_CNTL) - 
regSDMA0_SDMA_QUEUE0_RB_CNTL;
-               break;
-       default:
-               WARN(1, "Invalid SDMA engine id %d\n", engine_id);
-               break;
-       }
+       /*
+        * On SDMA v7 (gc_12_x) all SDMA queue registers live in the GC_HWIP
+        * aperture. The second SDMA per XCC is reached by adding a fixed
+        * offset (regSDMA1_* - regSDMA0_* == SDMA1_REG_OFFSET
+        */
+       sdma_engine_reg_base = adev->reg_offset[GC_HWIP][xcc_id][0];
+       if (xcc_inst != 0)
+               sdma_engine_reg_base +=
+                       regSDMA1_SDMA_QUEUE0_RB_CNTL - 
regSDMA0_SDMA_QUEUE0_RB_CNTL;
 
        sdma_rlc_reg_offset = sdma_engine_reg_base
                + queue_id * (regSDMA0_SDMA_QUEUE1_RB_CNTL - 
regSDMA0_SDMA_QUEUE0_RB_CNTL);
@@ -141,8 +137,7 @@ static int hqd_sdma_dump_v12_1(struct amdgpu_device *adev,
                             uint32_t engine_id, uint32_t queue_id,
                             uint32_t (**dump)[2], uint32_t *n_regs)
 {
-       uint32_t sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev,
-                       engine_id, queue_id);
+       uint32_t sdma_rlc_reg_offset;
        uint32_t i = 0, reg;
 
        const uint32_t first_reg = regSDMA0_SDMA_QUEUE0_RB_CNTL;
@@ -150,6 +145,17 @@ static int hqd_sdma_dump_v12_1(struct amdgpu_device *adev,
 #undef HQD_N_REGS
 #define HQD_N_REGS (last_reg - first_reg + 1)
 
+       /*
+        * dqm_debugfs_hqds() iterates engine_id over
+        * node_id * get_num_all_sdma_engines()..+get_num_all_sdma_engines().
+        * On partitioned devices that range can address a logical SDMA engine
+        * beyond the instances that actually exist on this node; reject it
+        */
+       if (engine_id >= adev->sdma.num_instances)
+               return -EINVAL;
+
+       sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev, engine_id, 
queue_id);
+
        *dump = kmalloc(HQD_N_REGS*2*sizeof(uint32_t), GFP_KERNEL);
        if (*dump == NULL)
                return -ENOMEM;
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 3ec6a73af22e..2ec337334dc5 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -4107,6 +4107,15 @@ int dqm_debugfs_hqds(struct seq_file *m, void *data)
                     queue++) {
                        r = dqm->dev->kfd2kgd->hqd_sdma_dump(
                                dqm->dev->adev, pipe, queue, &dump, &n_regs);
+                       if (r == -EINVAL) {
+                               /*
+                                * SDMA engine not present/mapped on this
+                                * device; skip it instead of aborting the
+                                * whole dump.
+                                */
+                               r = 0;
+                               break;
+                       }
                        if (r)
                                break;
 
-- 
2.43.0

Reply via email to