Implement detect_hung_queue() by matching enabled HQD doorbells over
MMIO, allowing GFX reset to locate the queue without a MES request.

Signed-off-by: Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 42 ++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index ec1e142549c5..96aacaf2fc27 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -912,6 +912,10 @@ static void gfx_v12_0_select_me_pipe_q(struct 
amdgpu_device *adev,
        soc24_grbm_select(adev, me, pipe, q, vm);
 }
 
+static bool gfx_v12_0_detect_hung_queue(struct amdgpu_device *adev,
+                                       u32 doorbell_index,
+                                       u32 *me, u32 *pipe, u32 *queue);
+
 /* all sizes are in bytes */
 #define MQD_SHADOW_BASE_SIZE      73728
 #define MQD_SHADOW_BASE_ALIGNMENT 256
@@ -951,6 +955,7 @@ static const struct amdgpu_gfx_funcs gfx_v12_0_gfx_funcs = {
        .read_wave_sgprs = &gfx_v12_0_read_wave_sgprs,
        .read_wave_vgprs = &gfx_v12_0_read_wave_vgprs,
        .select_me_pipe_q = &gfx_v12_0_select_me_pipe_q,
+       .detect_hung_queue = &gfx_v12_0_detect_hung_queue,
        .update_perfmon_mgcg = &gfx_v12_0_update_perf_clk,
        .get_gfx_shadow_info = &gfx_v12_0_get_gfx_shadow_info,
        .get_hdp_flush_mask = &amdgpu_gfx_get_hdp_flush_mask,
@@ -5046,6 +5051,43 @@ static int gfx_v12_0_set_priv_inst_fault_state(struct 
amdgpu_device *adev,
        return 0;
 }
 
+static bool gfx_v12_0_detect_hung_queue(struct amdgpu_device *adev,
+                                       u32 doorbell_index,
+                                       u32 *me, u32 *pipe, u32 *queue)
+{
+       u32 i, k, p, db_ctrl, dboff;
+       bool found = false;
+
+       amdgpu_gfx_off_ctrl(adev, false);
+       mutex_lock(&adev->srbm_mutex);
+       for (i = 0; i < adev->gfx.me.num_me && !found; i++) {
+               for (p = 0; p < adev->gfx.me.num_pipe_per_me && !found; p++) {
+                       for (k = 0; k < adev->gfx.me.num_queue_per_pipe; k++) {
+                               soc24_grbm_select(adev, i, p, k, 0);
+                               db_ctrl = RREG32_SOC15(GC, 0,
+                                                      
regCP_RB_DOORBELL_CONTROL);
+                               if (!(db_ctrl & 
CP_RB_DOORBELL_CONTROL__DOORBELL_EN_MASK))
+                                       continue;
+                               dboff = (db_ctrl &
+                                        
CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK) >>
+                                       
CP_RB_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+                               if (dboff == doorbell_index) {
+                                       *me = i;
+                                       *pipe = p;
+                                       *queue = k;
+                                       found = true;
+                                       break;
+                               }
+                       }
+               }
+       }
+       soc24_grbm_select(adev, 0, 0, 0, 0);
+       mutex_unlock(&adev->srbm_mutex);
+       amdgpu_gfx_off_ctrl(adev, true);
+
+       return found;
+}
+
 /*
  * A gfx exception IV carries no doorbell. For each faulted slot, read the
  * doorbell back from the HQD (left in place by the fatal fault), look up the
-- 
2.49.0

Reply via email to