to implement AMDGPU_SPM_OP_RELEASE, which stops the SPM hardware, drains
the work queue, unblocks any waiting SET_DEST_BUF callers, and frees
all per-XCC ring buffer resources acquired by AMDGPU_SPM_OP_ACQUIRE.

_amdgpu_spm_release(spm_mgr, inst, filp):
  Per-XCC teardown helper. Skips silently if the ring buffer was never
  allocated (ring_size == 0). Otherwise:
  - Calls amdgpu_rlc_spm_release() to stop the RLC hardware, revert
    the SPM VMID to 0xf, and free the reserved VMID on the GFX hub.
  - Calls amdgpu_bo_free_gtt_mem() to unpin, unmap, and drop the 4 MiB
    GTT ring buffer BO.
  - Under spm_irq_lock, zeroes the entire amdgpu_spm_base entry to
    prevent stale pointer access from any concurrent IRQ path.
  - Decrements spm_use_cnt.

amdgpu_spm_release(spm_mgr, filp):
  1. Takes the per-XCP prof_xcp_mgr->mutex to serialize against
     concurrent ACQUIRE or SET_DEST_BUF calls.
  2. Returns -EPERM if the caller's drm_file does not match
     spm_mgr->file, preventing one process from releasing another's
     SPM session.
  3. Returns -EINVAL if SPM was never acquired (spm_cntr == NULL).
  4. For each XCC in AMDGPU_XCC_MASK(adev): clears is_spm_started
     under spm_irq_lock, then stops the hardware via
     amdgpu_rlc_spm_cntl(stop).
  5. Calls flush_work() to wait for any in-progress ring drain to
     complete before freeing buffers.
  6. Calls wake_up_all() on spm_buf_wq to unblock any thread sleeping
     in SET_DEST_BUF with a pending timeout.
  7. Calls _amdgpu_spm_release() for each XCC to free per-XCC resources.
  8. Calls amdgpu_vmid_free_reserved() to release the GFX hub VMID
     reservation on hub 0.
  9. Destroys spm_worker_mutex, frees spm_cntr, and sets spm_cntr = NULL
     under spm_irq_lock to prevent the IRQ handler from scheduling new
     work after the memory is freed.

Signed-off-by: James Zhu <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c | 56 +++++++++++++++++++++++--
 1 file changed, 53 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
index 896a0fef576c..d4af195bbcd2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_spm.c
@@ -150,14 +150,61 @@ static int amdgpu_spm_acquire(struct amdgpu_spm_mgr 
*spm_mgr, struct drm_file *f
 
 static void _amdgpu_spm_release(struct amdgpu_spm_mgr *spm_mgr, int inst, 
struct drm_file *filp)
 {
-       /* TODO: */
+       struct amdgpu_device *adev = mgr_to_adev(spm_mgr, spm_mgr);
+       struct amdgpu_spm_base *spm = &(spm_mgr->spm_cntr->spm[inst]);
+       unsigned long flags;
+
+       if (!spm->ring_size)
+               return;
+       amdgpu_rlc_spm_release(adev, inst, drm_priv_to_vm(filp));
+       amdgpu_bo_free_gtt_mem(adev, &(spm->spm_obj));
+
+       spin_lock_irqsave(&spm_mgr->spm_irq_lock, flags);
+       memset(spm, 0, sizeof(*spm));
+       spin_unlock_irqrestore(&spm_mgr->spm_irq_lock, flags);
 
+       --spm_mgr->spm_cntr->spm_use_cnt;
 }
 
 static int amdgpu_spm_release(struct amdgpu_spm_mgr *spm_mgr, struct drm_file 
*filp)
 {
-       /* TODO */
-       return 0;
+       struct amdgpu_device *adev = mgr_to_adev(spm_mgr, spm_mgr);
+       unsigned long flags;
+       int inst;
+       int ret = 0;
+
+       mutex_lock(&(to_prof_xcp_mgr(spm_mgr, spm_mgr)->mutex));
+       if (spm_mgr->file != filp) {
+               ret = -EPERM;
+               goto out;
+       }
+       if (!spm_mgr->spm_cntr) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for_each_inst(inst, AMDGPU_XCC_MASK(adev)) {
+               spin_lock_irqsave(&spm_mgr->spm_irq_lock, flags);
+               spm_mgr->spm_cntr->spm[inst].is_spm_started = false;
+               spin_unlock_irqrestore(&spm_mgr->spm_irq_lock, flags);
+               amdgpu_rlc_spm_cntl(adev, inst, 0);
+       }
+       flush_work(&spm_mgr->spm_work);
+       wake_up_all(&spm_mgr->spm_cntr->spm_buf_wq);
+
+       for_each_inst(inst, AMDGPU_XCC_MASK(adev))
+               _amdgpu_spm_release(spm_mgr, inst, filp);
+       amdgpu_vmid_free_reserved(adev, drm_priv_to_vm(filp), AMDGPU_GFXHUB(0));
+
+       mutex_destroy(&(spm_mgr->spm_cntr->spm_worker_mutex));
+       kfree(spm_mgr->spm_cntr);
+       spin_lock_irqsave(&spm_mgr->spm_irq_lock, flags);
+       spm_mgr->spm_cntr = NULL;
+       spin_unlock_irqrestore(&spm_mgr->spm_irq_lock, flags);
+
+out:
+       mutex_unlock(&(to_prof_xcp_mgr(spm_mgr, spm_mgr)->mutex));
+       return ret;
 }
 
 static int spm_update_dest_info(struct amdgpu_spm_mgr *spm_mgr,
@@ -365,6 +412,9 @@ int amdgpu_spm_ioctl(struct drm_device *dev, void *data,
        case AMDGPU_SPM_OP_ACQUIRE:
                return amdgpu_spm_acquire(spm_mgr, filp);
 
+       case AMDGPU_SPM_OP_RELEASE:
+               return amdgpu_spm_release(spm_mgr, filp);
+
        case AMDGPU_SPM_OP_SET_DEST_BUF:
                return amdgpu_set_dest_buffer(spm_mgr, data);
 
-- 
2.34.1

Reply via email to