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

Reply via email to