to introduce the hardware-agnostic RLC (Run List Controller) SPM interface
layer that sits between the generic SPM manager and IP-specific register
programming.

A new function table struct amdgpu_spm_funcs is added to amdgpu_gfx.h,
with the following callbacks to be implemented per IP version:
  - start(adev, xcc_id):   enable SPM hardware and interrupt
  - stop(adev, xcc_id):    disable SPM hardware and interrupt
  - set_rdptr(adev, xcc_id, rptr): update the SPM ring read pointer
  - set_spm_perfmon_ring_buf(adev, xcc_id, gpu_addr, size): configure
    the SPM ring buffer base address and size registers
  - set_spm_config_size: KIQ ring space (in DWORDs) needed per operation

A pointer to the active function table is stored in adev->gfx.spmfuncs.
All RLC SPM functions are no-ops when spmfuncs is NULL.

Five generic RLC SPM functions are implemented in amdgpu_rlc.c:
  amdgpu_rlc_spm_acquire(adev, xcc_id, vm, gpu_addr, size):
    Sets up SPM for a specific XCP instance. Allocates a reserved VMID
    on the GFX hub for the caller's VM, initializes the SPM VMID to 0x0
    (from the default 0xf), then programs the ring buffer base address
    and size via the KIQ ring. On failure, reverts the VMID to 0xf and
    frees the reserved VMID.

  amdgpu_rlc_spm_release(adev, xcc_id, vm):
    Stops the SPM stream via the KIQ ring, reverts the SPM VMID to 0xf,
    and frees the reserved VMID.

  amdgpu_rlc_spm_cntl(adev, xcc_id, cntl):
    Starts (cntl=true) or stops (cntl=false) the SPM hardware by
    dispatching start()/stop() through the KIQ ring under the KIQ
    ring_lock spinlock.

  amdgpu_rlc_spm_set_rdptr(adev, xcc_id, rptr):
    Advances the SPM ring read pointer via the KIQ ring, informing the
    hardware that the CPU has consumed data up to rptr.

  amdgpu_rlc_spm_interrupt(adev, xcc_id):
    SPM interrupt handler stub.

All KIQ ring operations are serialized under the per-XCC KIQ ring_lock
spinlock.

Signed-off-by: James Zhu <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h | 11 +++
 drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c | 90 +++++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h |  6 ++
 3 files changed, 107 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
index 720ed3a2c78c..016eed89d6f3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h
@@ -164,6 +164,16 @@ struct amdgpu_kiq {
        void                    *mqd_backup;
 };
 
+struct amdgpu_spm_funcs {
+       void (*start)(struct amdgpu_device *adev, int xcc_id);
+       void (*stop)(struct amdgpu_device *adev, int xcc_id);
+       void (*set_rdptr)(struct amdgpu_device *adev, int xcc_id, u32 rptr);
+       void (*set_spm_perfmon_ring_buf)(struct amdgpu_device *adev, int xcc_id,
+                               u64 gpu_rptr, u32 size);
+       /* Packet sizes */
+       int set_spm_config_size;
+};
+
 /*
  * GFX configurations
  */
@@ -418,6 +428,7 @@ struct amdgpu_gfx {
        struct amdgpu_mec_bitmap        mec_bitmap[AMDGPU_MAX_GC_INSTANCES];
        struct amdgpu_kiq               kiq[AMDGPU_MAX_GC_INSTANCES];
        struct amdgpu_imu               imu;
+       const struct amdgpu_spm_funcs           *spmfuncs;
        bool                            rs64_enable; /* firmware format */
        const struct firmware           *me_fw; /* ME firmware */
        uint32_t                        me_fw_version;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
index 572a60e1b3cb..faf2a34df42f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c
@@ -583,3 +583,93 @@ int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device 
*adev,
                amdgpu_gfx_rlc_init_microcode_v2_5(adev);
        return 0;
 }
+
+void amdgpu_rlc_spm_cntl(struct amdgpu_device *adev, int xcc_id, bool cntl)
+{
+       struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[xcc_id].ring;
+
+       if (!adev->gfx.spmfuncs)
+               return;
+
+       spin_lock(&adev->gfx.kiq[xcc_id].ring_lock);
+       amdgpu_ring_alloc(kiq_ring, adev->gfx.spmfuncs->set_spm_config_size);
+       if (cntl)
+               adev->gfx.spmfuncs->start(adev, xcc_id);
+       else
+               adev->gfx.spmfuncs->stop(adev, xcc_id);
+       amdgpu_ring_commit(kiq_ring);
+       spin_unlock(&adev->gfx.kiq[xcc_id].ring_lock);
+}
+
+void amdgpu_rlc_spm_set_rdptr(struct amdgpu_device *adev, int xcc_id, u32 rptr)
+{
+       struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[xcc_id].ring;
+
+       if (!adev->gfx.spmfuncs)
+               return;
+
+       spin_lock(&adev->gfx.kiq[xcc_id].ring_lock);
+       amdgpu_ring_alloc(kiq_ring, adev->gfx.spmfuncs->set_spm_config_size);
+       adev->gfx.spmfuncs->set_rdptr(adev, xcc_id, rptr);
+       amdgpu_ring_commit(kiq_ring);
+       spin_unlock(&adev->gfx.kiq[xcc_id].ring_lock);
+}
+
+int amdgpu_rlc_spm_acquire(struct amdgpu_device *adev, int xcc_id,
+                       struct amdgpu_vm *vm, u64 gpu_addr, u32 size)
+{
+       struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[xcc_id].ring;
+       int r = 0;
+
+       if (!adev->gfx.spmfuncs ||
+               !adev->gfx.rlc.funcs->update_spm_vmid)
+               return -EINVAL;
+
+       r = amdgpu_vmid_alloc_reserved(adev, vm, AMDGPU_GFXHUB(xcc_id));
+       if (r)
+               return r;
+
+       /* init spm vmid with 0x0 */
+       adev->gfx.rlc.funcs->update_spm_vmid(adev, xcc_id, NULL, 0);
+
+       /* set spm ring registers */
+       spin_lock(&adev->gfx.kiq[xcc_id].ring_lock);
+       r = amdgpu_ring_alloc(kiq_ring, 
adev->gfx.spmfuncs->set_spm_config_size);
+       if (!r) {
+               adev->gfx.spmfuncs->set_spm_perfmon_ring_buf(adev, xcc_id, 
gpu_addr, size);
+               amdgpu_ring_commit(kiq_ring);
+       }
+       spin_unlock(&adev->gfx.kiq[xcc_id].ring_lock);
+
+       if (r) {
+               adev->gfx.rlc.funcs->update_spm_vmid(adev, xcc_id, NULL, 0xf);
+               amdgpu_vmid_free_reserved(adev, vm, AMDGPU_GFXHUB(xcc_id));
+       }
+       return r;
+}
+
+void amdgpu_rlc_spm_release(struct amdgpu_device *adev, int xcc_id, struct 
amdgpu_vm *vm)
+{
+       struct amdgpu_ring *kiq_ring = &adev->gfx.kiq[xcc_id].ring;
+
+       if (!adev->gfx.spmfuncs)
+               return;
+
+       /* stop spm stream and interrupt */
+       spin_lock(&adev->gfx.kiq[xcc_id].ring_lock);
+       amdgpu_ring_alloc(kiq_ring, adev->gfx.spmfuncs->set_spm_config_size);
+       adev->gfx.spmfuncs->stop(adev, xcc_id);
+       amdgpu_ring_commit(kiq_ring);
+       spin_unlock(&adev->gfx.kiq[xcc_id].ring_lock);
+
+       /* revert spm vmid with 0xf */
+       if (adev->gfx.rlc.funcs->update_spm_vmid) {
+               adev->gfx.rlc.funcs->update_spm_vmid(adev, xcc_id, NULL, 0xf);
+               amdgpu_vmid_free_reserved(adev, vm, AMDGPU_GFXHUB(xcc_id));
+       }
+}
+
+void amdgpu_rlc_spm_interrupt(struct amdgpu_device *adev, int xcc_id)
+{
+       /* TODO: */
+}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h
index e535534237a1..c5da9e428c8a 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h
@@ -374,4 +374,10 @@ void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev);
 int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev,
                                  uint16_t version_major,
                                  uint16_t version_minor);
+void amdgpu_rlc_spm_cntl(struct amdgpu_device *adev, int xcc_id, bool cntl);
+int amdgpu_rlc_spm_acquire(struct amdgpu_device *adev, int xcc_id,
+               struct amdgpu_vm *vm, u64 gpu_addr, u32 size);
+void amdgpu_rlc_spm_release(struct amdgpu_device *adev, int xcc_id, struct 
amdgpu_vm *vm);
+void amdgpu_rlc_spm_set_rdptr(struct amdgpu_device *adev, int xcc_id, u32 
rptr);
+void amdgpu_rlc_spm_interrupt(struct amdgpu_device *adev, int xcc_id);
 #endif
-- 
2.34.1

Reply via email to