Add the gfx_v12_0_spm_funcs backend. Ring setup writes RLC_SPM_PERFMON_RING_BASE_LO/HI, _RING_SIZE, the segment threshold and clears CP_CP_PERFMON_CNTL. start selects PERFMON_RING_MODE in RLC_SPM_PERFMON_CNTL, resets the perfmon state through CP_CP_PERFMON_CNTL, clears RLC_SPM_ACCUM_MODE and rewinds both RLC_SPM_RING_WRPTR and RLC_SPM_RING_RDPTR; stop stops counting, resets the perfmon state and rewinds the pointers again. set_rdptr updates RLC_SPM_RING_RDPTR as the consumer drains the ring. All callbacks bracket their register access with amdgpu_gfx_off_ctrl() so GFXOFF cannot swallow the writes, and program GET_INST(GC, 0) since gfx12 is single-XCC.
Add the gfx.spm_irq source for GFX_12_0_0__SRCID__RLC_STRM_PERF_MONITOR_INTERRUPT on SOC15_IH_CLIENTID_RLC, toggle it through RLC_SPM_INT_CNTL in the set-interrupt-state callback, take a reference in hw_init and drop it in hw_fini, and forward the interrupt to the SPM manager via amdgpu_rlc_spm_interrupt(). Because gfx12 reports ring progress by interrupt, no polling thread is needed. Signed-off-by: James Zhu <[email protected]> --- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 133 +++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index 398e9c463ec6..e02ab1046fb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -272,6 +272,8 @@ static void gfx_v12_0_set_mqd_funcs(struct amdgpu_device *adev); static void gfx_v12_0_set_imu_funcs(struct amdgpu_device *adev); static int gfx_v12_0_get_cu_info(struct amdgpu_device *adev, struct amdgpu_cu_info *cu_info); +static void gfx_v12_0_update_spm_vmid(struct amdgpu_device *adev, + int xcc_id, struct amdgpu_ring *ring, unsigned vmid); static uint64_t gfx_v12_0_get_gpu_clock_counter(struct amdgpu_device *adev); static void gfx_v12_0_select_se_sh(struct amdgpu_device *adev, u32 se_num, u32 sh_num, u32 instance, int xcc_id); @@ -1467,6 +1469,13 @@ static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block) num_compute_rings); } + /* SPM */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_RLC, + GFX_12_0_0__SRCID__RLC_STRM_PERF_MONITOR_INTERRUPT, + &adev->gfx.spm_irq); + if (r) + return r; + /* EOP Event */ r = amdgpu_irq_add_id(adev, SOC21_IH_CLIENTID_GRBM_CP, GFX_12_0_0__SRCID__CP_EOP_INTERRUPT, @@ -3854,6 +3863,10 @@ static int gfx_v12_0_hw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + r = amdgpu_irq_get(adev, &adev->gfx.spm_irq, 0); + if (r) + goto err_spm_irq; + r = amdgpu_irq_get(adev, &adev->gfx.priv_inst_irq, 0); if (r) goto err_priv_inst; @@ -3873,6 +3886,8 @@ static int gfx_v12_0_hw_init(struct amdgpu_ip_block *ip_block) err_bad_op: amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); err_priv_inst: + amdgpu_irq_put(adev, &adev->gfx.spm_irq, 0); +err_spm_irq: amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); return r; } @@ -3887,6 +3902,7 @@ static int gfx_v12_0_hw_fini(struct amdgpu_ip_block *ip_block) gfx_v12_0_set_userq_eop_interrupts(adev, false); amdgpu_irq_put(adev, &adev->gfx.bad_op_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); + amdgpu_irq_put(adev, &adev->gfx.spm_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); if (!adev->no_hw_access) { @@ -3972,6 +3988,85 @@ static uint64_t gfx_v12_0_get_gpu_clock_counter(struct amdgpu_device *adev) return clock; } +static void gfx_v12_0_spm_start(struct amdgpu_device *adev, int xcc_id) +{ + uint32_t data = 0; + + amdgpu_gfx_off_ctrl(adev, false); + + data = RREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_PERFMON_CNTL); + data |= RLC_SPM_PERFMON_CNTL__PERFMON_RING_MODE_MASK; + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_PERFMON_CNTL, data); + + data = REG_SET_FIELD(0, CP_CP_PERFMON_CNTL, SPM_PERFMON_STATE, + CP_PERFMON_STATE_DISABLE_AND_RESET); + WREG32_SOC15(GC, GET_INST(GC, 0), regCP_CP_PERFMON_CNTL, data); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_ACCUM_MODE, 0); + + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_RING_WRPTR, 0); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_RING_RDPTR, 0); + + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_INT_CNTL, 1); + + amdgpu_gfx_off_ctrl(adev, true); +} + +static void gfx_v12_0_spm_stop(struct amdgpu_device *adev, int xcc_id) +{ + uint32_t data = 0; + + amdgpu_gfx_off_ctrl(adev, false); + + data = REG_SET_FIELD(0, CP_CP_PERFMON_CNTL, SPM_PERFMON_STATE, + CP_PERFMON_STATE_STOP_COUNTING); + WREG32_SOC15(GC, GET_INST(GC, 0), regCP_CP_PERFMON_CNTL, data); + + data = REG_SET_FIELD(0, CP_CP_PERFMON_CNTL, SPM_PERFMON_STATE, + CP_PERFMON_STATE_DISABLE_AND_RESET); + WREG32_SOC15(GC, GET_INST(GC, 0), regCP_CP_PERFMON_CNTL, data); + + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_RING_WRPTR, 0); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_RING_RDPTR, 0); + + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_INT_CNTL, 0); + + amdgpu_gfx_off_ctrl(adev, true); +} + +static void gfx_v12_0_spm_set_rdptr(struct amdgpu_device *adev, int xcc_id, u32 rptr) +{ + amdgpu_gfx_off_ctrl(adev, false); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_RING_RDPTR, rptr); + amdgpu_gfx_off_ctrl(adev, true); +} + +static void gfx_v12_0_set_spm_perfmon_ring_buf(struct amdgpu_device *adev, + int xcc_id, u64 gpu_addr, u32 size) +{ + amdgpu_gfx_off_ctrl(adev, false); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_PERFMON_RING_BASE_LO, + lower_32_bits(gpu_addr)); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_PERFMON_RING_BASE_HI, + upper_32_bits(gpu_addr)); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_PERFMON_RING_SIZE, size); + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_SEGMENT_THRESHOLD, 0x1); + WREG32_SOC15(GC, GET_INST(GC, 0), regCP_CP_PERFMON_CNTL, 0); + amdgpu_gfx_off_ctrl(adev, true); +} + +static const struct amdgpu_spm_funcs gfx_v12_0_spm_funcs = { + .start = &gfx_v12_0_spm_start, + .stop = &gfx_v12_0_spm_stop, + .set_rdptr = &gfx_v12_0_spm_set_rdptr, + .set_spm_perfmon_ring_buf = &gfx_v12_0_set_spm_perfmon_ring_buf, + .set_spm_config_size = 0, +}; + +static void gfx_v12_0_set_spm_funcs(struct amdgpu_device *adev) +{ + adev->gfx.spmfuncs = &gfx_v12_0_spm_funcs; +} + static int gfx_v12_0_early_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -4004,6 +4099,7 @@ static int gfx_v12_0_early_init(struct amdgpu_ip_block *ip_block) AMDGPU_MAX_COMPUTE_RINGS); } + gfx_v12_0_set_spm_funcs(adev); gfx_v12_0_set_kiq_pm4_funcs(adev); gfx_v12_0_set_ring_funcs(adev); gfx_v12_0_set_irq_funcs(adev); @@ -5505,11 +5601,48 @@ static const struct amdgpu_irq_src_funcs gfx_v12_0_priv_inst_irq_funcs = { .process = gfx_v12_0_priv_inst_irq, }; +static int gfx_v12_0_spm_set_interrupt_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *src, + unsigned int type, + enum amdgpu_interrupt_state state) +{ + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_INT_CNTL, 0); + break; + case AMDGPU_IRQ_STATE_ENABLE: + WREG32_SOC15(GC, GET_INST(GC, 0), regRLC_SPM_INT_CNTL, 1); + break; + default: + break; + } + + + return 0; +} + +static int gfx_v12_0_set_spm_irq(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + struct amdgpu_iv_entry *entry) +{ + amdgpu_rlc_spm_interrupt(adev, 0); + return 0; +} + +static const struct amdgpu_irq_src_funcs gfx_v12_0_set_spm_irq_funcs = { + .set = gfx_v12_0_spm_set_interrupt_state, + .process = gfx_v12_0_set_spm_irq, +}; + static void gfx_v12_0_set_irq_funcs(struct amdgpu_device *adev) { adev->gfx.eop_irq.num_types = AMDGPU_CP_IRQ_LAST; adev->gfx.eop_irq.funcs = &gfx_v12_0_eop_irq_funcs; + adev->gfx.spm_irq.num_types = 1; + adev->gfx.spm_irq.funcs = &gfx_v12_0_set_spm_irq_funcs; + adev->gfx.priv_reg_irq.num_types = 1; adev->gfx.priv_reg_irq.funcs = &gfx_v12_0_priv_reg_irq_funcs; -- 2.34.1
