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
