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