Add the per-IP hardware wiring that drives the mes_dbgext core on gfx11
(mes_v11_0 / gfx_v11_0) and gfx12 (mes_v12_0 / gfx_v12_0): handle
MES_MISC_OP_SETUP_MES_DBGEXT in the misc-op path, unmask the MES debug
interrupt, select the flat (gfx11) or zoned (gfx12) buffer format in
sw_init(), start/stop the feature from hw_init()/hw_fini(), and drain
the log from the EOP interrupt handler while the feature is active.

Signed-off-by: Yongqiang Sun <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 12 ++++++
 drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 18 +++++++++
 drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 40 ++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/mes_v12_0.c | 52 ++++++++++++++++++++++++++
 4 files changed, 122 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
index a7ed4923857b..c14e2e0890ce 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
@@ -6534,6 +6534,18 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev,
 
        DRM_DEBUG("IH: CP EOP\n");
 
+       /*
+        * MES firmware debug-extension ("mes_dbgext") messages are delivered as
+        * an EOP interrupt from the MES pipe (me 3), carrying MES_DBGMSG (type 
7)
+        * in the top 6 bits of the context word.  Route them to the mes_dbgext
+        * drain instead of the (gfx/compute) EOP fence handling below.
+        */
+       if (((entry->ring_id & 0x0c) >> 2) == 3 &&
+           (entry->src_data[0] >> 26) == 7) {
+               amdgpu_mes_dbgext_notify(adev, entry->src_data[0]);
+               return 0;
+       }
+
        if (!adev->gfx.disable_kq) {
                u8 me_id = (entry->ring_id & 0x0c) >> 2;
                u8 pipe_id = (entry->ring_id & 0x03) >> 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
index ec1e142549c5..9ba2846e48fe 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c
@@ -4871,6 +4871,24 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev,
 
        DRM_DEBUG("IH: CP EOP\n");
 
+       /*
+        * MES firmware host interrupts - including the mes_dbgext debug-message
+        * notification - are raised via the RS64 host-interrupt path (the
+        * firmware triggers the CPC TIME_STAMP assertion).  Although the 
firmware
+        * tags the cookie with src_id CP_GENERIC_INT (177), the CP actually
+        * delivers this to the host IH as a CP EOP (src_id 181) on the MES
+        * scheduler pipe (me 3) - so it arrives through the normal CP_EOP
+        * registration, not a CP_GENERIC_INT one.  The gfx12 IH cookie does not
+        * preserve the MES interrupt type, so when dbgext is active, drain on 
any
+        * me3 EOP; draining is a no-op when the log buffer has no new data, and
+        * returning early keeps it out of the (gfx/compute/userq) fence paths.
+        */
+       if (adev->mes.dbgext_active &&
+           ((entry->ring_id & 0x0c) >> 2) == 3) {
+               amdgpu_mes_dbgext_notify(adev, entry->src_data[0]);
+               return 0;
+       }
+
        if (!adev->gfx.disable_kq) {
                u8 me_id = (entry->ring_id & 0x0c) >> 2;
                u8 pipe_id = (entry->ring_id & 0x03) >> 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c 
b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
index 51bfb672bed7..4a5ed502cedc 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c
@@ -969,6 +969,13 @@ static int mes_v11_0_misc_op(struct amdgpu_mes *mes,
                misc_pkt.opcode = MESAPI_MISC__NOTIFY_WORK_ON_UNMAPPED_QUEUE;
                misc_pkt.queue_sch_level = AMD_PRIORITY_LEVEL_NORMAL;
                break;
+       case MES_MISC_OP_SETUP_MES_DBGEXT:
+               misc_pkt.opcode = MESAPI_MISC__SETUP_MES_DBGEXT;
+               misc_pkt.dbgext_init_data.dbg_ext_mc_addr =
+                               input->setup_mes_dbgext.log_buffer_mc_addr;
+               misc_pkt.dbgext_init_data.u64_all =
+                               input->setup_mes_dbgext.log_options;
+               break;
        default:
                drm_err(adev_to_drm(mes->adev), "unsupported misc op (%d)\n", 
input->op);
                return -EINVAL;
@@ -1144,6 +1151,32 @@ static int mes_v11_0_detect_and_reset_hung_queues(struct 
amdgpu_mes *mes,
                        offsetof(union MESAPI__RESET, api_status));
 }
 
+/*
+ * Enable/disable delivery of the MES firmware host interrupts at the CP.  The
+ * MES firmware debug-message interrupt is delivered as a CP EOP from the MES
+ * pipe (me 3) and handled in gfx_v11_0_eop_irq(); it is gated by CPC_INT_CNTL
+ * in that ME/pipe context, selected via GRBM_GFX_CNTL.  Mirrors the Windows 
KMD
+ * MES interrupt-enable path.  Must run in process context (takes srbm_mutex).
+ */
+static int mes_v11_0_enable_dbgext_irq(struct amdgpu_mes *mes, bool enable)
+{
+       struct amdgpu_device *adev = mes->adev;
+       u32 cp_int_cntl;
+
+       mutex_lock(&adev->srbm_mutex);
+       soc21_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0);
+
+       cp_int_cntl = RREG32_SOC15(GC, 0, regCPC_INT_CNTL);
+       cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CPC_INT_CNTL,
+                                       TIME_STAMP_INT_ENABLE, enable ? 1 : 0);
+       WREG32_SOC15(GC, 0, regCPC_INT_CNTL, cp_int_cntl);
+
+       soc21_grbm_select(adev, 0, 0, 0, 0);
+       mutex_unlock(&adev->srbm_mutex);
+
+       return 0;
+}
+
 static const struct amdgpu_mes_funcs mes_v11_0_funcs = {
        .add_hw_queue = mes_v11_0_add_hw_queue,
        .remove_hw_queue = mes_v11_0_remove_hw_queue,
@@ -1152,6 +1185,7 @@ static const struct amdgpu_mes_funcs mes_v11_0_funcs = {
        .suspend_gang = mes_v11_0_suspend_gang,
        .resume_gang = mes_v11_0_resume_gang,
        .misc_op = mes_v11_0_misc_op,
+       .enable_dbgext_irq = mes_v11_0_enable_dbgext_irq,
        .reset_hw_queue = mes_v11_0_reset_hw_queue,
        .detect_and_reset_hung_queues = mes_v11_0_detect_and_reset_hung_queues,
 };
@@ -2049,6 +2083,8 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block 
*ip_block)
        adev->gfx.kiq[0].ring.sched.ready = false;
        adev->mes.ring[0].sched.ready = true;
 
+       amdgpu_mes_dbgext_start(adev);
+
        return 0;
 
 failure:
@@ -2058,6 +2094,10 @@ static int mes_v11_0_hw_init(struct amdgpu_ip_block 
*ip_block)
 
 static int mes_v11_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
+       struct amdgpu_device *adev = ip_block->adev;
+
+       amdgpu_mes_dbgext_stop(adev);
+
        return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c 
b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
index 9d220bff0f6f..363e1d6d3c2b 100644
--- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c
@@ -910,6 +910,13 @@ static int mes_v12_0_misc_op(struct amdgpu_mes *mes,
                misc_pkt.change_config.option.bits.limit_single_process =
                                
input->change_config.option.limit_single_process;
                break;
+       case MES_MISC_OP_SETUP_MES_DBGEXT:
+               misc_pkt.opcode = MESAPI_MISC__SETUP_MES_DBGEXT;
+               misc_pkt.dbgext_init_data.dbg_ext_mc_addr =
+                               input->setup_mes_dbgext.log_buffer_mc_addr;
+               misc_pkt.dbgext_init_data.u64_all =
+                               input->setup_mes_dbgext.log_options;
+               break;
 
        default:
                DRM_ERROR("unsupported misc op (%d)\n", input->op);
@@ -1213,6 +1220,45 @@ static int mes_v12_0_inv_tlbs_pasid(struct amdgpu_mes 
*mes,
 
 }
 
+/*
+ * Enable/disable delivery of the MES firmware host interrupts at the CP.  The
+ * MES firmware debug-message ("mes_dbgext") interrupt is delivered to the IH
+ * as a CP EOP (src_id 181) on the MES scheduler pipe (me 3) and handled in
+ * gfx_v12_0_eop_irq(); it is gated by CPC_INT_CNTL in the me3/MES pipe 
context,
+ * selected via GRBM_GFX_CNTL.  Must run in process context (takes srbm_mutex).
+ *
+ * Although the firmware C code passes Rs64HostIntrGeneric1IntEnable, the RS64
+ * library routine that actually raises the interrupt (AsmRs64SetHostIntr)
+ * hardcodes the TIME_STAMP assertion bit (CP_INT_STAT_DEBUG bit 26).  So
+ * TIME_STAMP_INT_ENABLE - not GENERIC1_INT_ENABLE - is the CPC_INT_CNTL bit
+ * that lets the CP forward the assertion to the host IH.  CPC_INT_CNTL is
+ * per-(me,pipe); the enable must be set on both me3 pipes (0 and 1), matching
+ * the Windows/SR-IOV KMD path - setting it only on the scheduler pipe is not
+ * sufficient.
+ */
+static int mes_v12_0_enable_dbgext_irq(struct amdgpu_mes *mes, bool enable)
+{
+       struct amdgpu_device *adev = mes->adev;
+       u32 cp_int_cntl;
+       int pipe;
+
+       mutex_lock(&adev->srbm_mutex);
+
+       for (pipe = 0; pipe < 2; pipe++) {
+               soc24_grbm_select(adev, 3, pipe, 0, 0);
+
+               cp_int_cntl = RREG32_SOC15(GC, 0, regCPC_INT_CNTL);
+               cp_int_cntl = REG_SET_FIELD(cp_int_cntl, CPC_INT_CNTL,
+                                           TIME_STAMP_INT_ENABLE, enable ? 1 : 
0);
+               WREG32_SOC15(GC, 0, regCPC_INT_CNTL, cp_int_cntl);
+       }
+
+       soc24_grbm_select(adev, 0, 0, 0, 0);
+       mutex_unlock(&adev->srbm_mutex);
+
+       return 0;
+}
+
 static const struct amdgpu_mes_funcs mes_v12_0_funcs = {
        .add_hw_queue = mes_v12_0_add_hw_queue,
        .remove_hw_queue = mes_v12_0_remove_hw_queue,
@@ -1224,6 +1270,7 @@ static const struct amdgpu_mes_funcs mes_v12_0_funcs = {
        .reset_hw_queue = mes_v12_0_reset_hw_queue,
        .invalidate_tlbs_pasid = mes_v12_0_inv_tlbs_pasid,
        .detect_and_reset_hung_queues = mes_v12_0_detect_and_reset_hung_queues,
+       .enable_dbgext_irq = mes_v12_0_enable_dbgext_irq,
 };
 
 static int mes_v12_0_allocate_ucode_buffer(struct amdgpu_device *adev,
@@ -2114,6 +2161,8 @@ static int mes_v12_0_hw_init(struct amdgpu_ip_block 
*ip_block)
        adev->gfx.kiq[0].ring.sched.ready = false;
        adev->mes.ring[0].sched.ready = true;
 
+       amdgpu_mes_dbgext_start(adev);
+
        return 0;
 
 failure:
@@ -2123,6 +2172,9 @@ static int mes_v12_0_hw_init(struct amdgpu_ip_block 
*ip_block)
 
 static int mes_v12_0_hw_fini(struct amdgpu_ip_block *ip_block)
 {
+       struct amdgpu_device *adev = ip_block->adev;
+
+       amdgpu_mes_dbgext_stop(adev);
        return 0;
 }
 
-- 
2.43.0

Reply via email to