From: Pierre-Eric Pelloux-Prayer <[email protected]>
Creating a job will now wake up the GPU. The rpm ref will be dropped either in amdgpu_ib_schedule (because at this point the amdgpu_fence took a ref) or in amdgpu_job_free (for unsubmitted jobs). Jobs submitted directly are a bit tricky because they might be fired from suspend/resume sequence and for now they're left unmodified. Signed-off-by: Pierre-Eric Pelloux-Prayer <[email protected]> Signed-off-by: Shahyan Soltani <[email protected]> --- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 15 +++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 42 +++++++++++++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 2 ++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 0f8b097001e3..3b55dd6ce8a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -27,6 +27,7 @@ * Christian König */ #include <linux/seq_file.h> +#include <linux/pm_runtime.h> #include <drm/amdgpu_drm.h> #include "amdgpu.h" @@ -297,8 +298,18 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, struct amdgpu_job *job, amdgpu_fence_emit(ring, af, fence_flags); *f = &af->base; - /* get a ref for the job */ - dma_fence_get(*f); + + if (job) { + /* get a ref for the job */ + dma_fence_get(*f); + /* now that the fence has been sent to the hw, we can drop + * our pm ref. + */ + if (job->holds_pm_ref) { + pm_runtime_put_autosuspend(adev->dev); + job->holds_pm_ref = false; + } + } if (ring->funcs->insert_end) ring->funcs->insert_end(ring); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 0056a93c400a..417f2619dfb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -24,6 +24,7 @@ #include <linux/kthread.h> #include <linux/wait.h> #include <linux/sched.h> +#include <linux/pm_runtime.h> #include <drm/drm_drv.h> @@ -201,15 +202,24 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, unsigned int num_ibs, u64 drm_client_id, gfp_t gfp_flags, struct amdgpu_job **job) { + bool take_pm_ref = entity && !adev->in_runpm; struct amdgpu_fence *af; int r; if (num_ibs == 0) return -EINVAL; + if (take_pm_ref) { + r = pm_runtime_resume_and_get(adev->dev); + if (r < 0) + return r; + } + *job = kzalloc_flex(**job, ibs, num_ibs, gfp_flags); - if (!*job) - return -ENOMEM; + if (!*job) { + r = -ENOMEM; + goto out_pm; + } af = kzalloc_obj(struct amdgpu_fence, gfp_flags); if (!af) { @@ -230,6 +240,7 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, amdgpu_sync_create(&(*job)->explicit_sync); (*job)->generation = amdgpu_vm_generation(adev, vm); (*job)->vm_pd_addr = AMDGPU_BO_INVALID_OFFSET; + (*job)->holds_pm_ref = take_pm_ref; if (!entity) return 0; @@ -245,6 +256,9 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, err_job: kfree(*job); *job = NULL; +out_pm: + if (take_pm_ref) + pm_runtime_put_autosuspend(adev->dev); return r; } @@ -270,6 +284,8 @@ int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, kfree((*job)->hw_vm_fence); kfree((*job)->hw_fence); kfree(*job); + if ((*job)->holds_pm_ref) + pm_runtime_put_autosuspend(adev->dev); *job = NULL; } @@ -314,6 +330,17 @@ void amdgpu_job_free_resources(struct amdgpu_job *job) static void amdgpu_job_free_cb(struct drm_sched_job *s_job) { struct amdgpu_job *job = to_amdgpu_job(s_job); + struct amdgpu_ring *ring; + + if (job->holds_pm_ref && job->base.sched) { + ring = to_amdgpu_ring(job->base.sched); + WARN_ON(!ring); + + /* Should have been cleared on submit, but we have to drop + * it in case the job was cancelled. + */ + pm_runtime_put_autosuspend(ring->adev->dev); + } drm_sched_job_cleanup(s_job); @@ -349,9 +376,20 @@ void amdgpu_job_set_gang_leader(struct amdgpu_job *job, void amdgpu_job_free(struct amdgpu_job *job) { + struct amdgpu_ring *ring; + if (job->base.entity) drm_sched_job_cleanup(&job->base); + if (job->holds_pm_ref && job->base.sched) { + ring = to_amdgpu_ring(job->base.sched); + + /* Should have been cleared on submit, but we have to drop + * it in case the job was cancelled. + */ + pm_runtime_put_autosuspend(ring->adev->dev); + } + amdgpu_job_free_resources(job); amdgpu_sync_free(&job->explicit_sync); if (job->gang_submit != &job->base.s_fence->scheduled) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h index 7e03bd2ff639..e7ab7e38f6df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h @@ -101,6 +101,8 @@ struct amdgpu_job { bool enforce_isolation; bool run_cleaner_shader; + bool holds_pm_ref; + uint32_t num_ibs; struct amdgpu_ib ibs[]; }; -- 2.55.0
