This is useful for changing an entity's priority at runtime. Signed-off-by: Andres Rodriguez <andresx7 at gmail.com> --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 26 +++++++++++++++++++++++--- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 6 +++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index a203736..c19bb85 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -121,30 +121,31 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity, struct amd_sched_rq *rq, uint32_t jobs) { int r; if (!(sched && entity && rq)) return -EINVAL; memset(entity, 0, sizeof(struct amd_sched_entity)); INIT_LIST_HEAD(&entity->list); entity->rq = rq; entity->sched = sched; + spin_lock_init(&entity->rq_lock); spin_lock_init(&entity->queue_lock); r = kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL); if (r) return r; atomic_set(&entity->fence_seq, 0); entity->fence_context = dma_fence_context_alloc(2); return 0; } /** * Query if entity is initialized * * @sched Pointer to scheduler instance @@ -192,62 +193,79 @@ static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity) return true; } /** * Destroy a context entity * * @sched Pointer to scheduler instance * @entity The pointer to a valid scheduler entity * * Cleanup and free the allocated resources. */ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity) { - struct amd_sched_rq *rq = entity->rq; - if (!amd_sched_entity_is_initialized(sched, entity)) return; /** * The client will not queue more IBs during this fini, consume existing * queued IBs */ wait_event(sched->job_scheduled, amd_sched_entity_is_idle(entity)); - amd_sched_rq_remove_entity(rq, entity); + amd_sched_entity_set_rq(entity, NULL); + kfifo_free(&entity->job_queue); } static void amd_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb) { struct amd_sched_entity *entity = container_of(cb, struct amd_sched_entity, cb); entity->dependency = NULL; dma_fence_put(f); amd_sched_wakeup(entity->sched); } static void amd_sched_entity_clear_dep(struct dma_fence *f, struct dma_fence_cb *cb) { struct amd_sched_entity *entity = container_of(cb, struct amd_sched_entity, cb); entity->dependency = NULL; dma_fence_put(f); } +void amd_sched_entity_set_rq(struct amd_sched_entity *entity, + struct amd_sched_rq *rq) +{ + if (entity->rq == rq) + return; + + spin_lock(&entity->rq_lock); + + if (entity->rq) + amd_sched_rq_remove_entity(entity->rq, entity); + + entity->rq = rq; + if (rq) + amd_sched_rq_add_entity(rq, entity); + + spin_unlock(&entity->rq_lock); +} + bool amd_sched_dependency_optimized(struct dma_fence* fence, struct amd_sched_entity *entity) { struct amd_gpu_scheduler *sched = entity->sched; struct amd_sched_fence *s_fence; if (!fence || dma_fence_is_signaled(fence)) return false; if (fence->context == entity->fence_context) return true; s_fence = to_amd_sched_fence(fence); if (s_fence && s_fence->sched == sched) return true; return false; @@ -321,31 +339,33 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job) struct amd_sched_entity *entity = sched_job->s_entity; bool added, first = false; spin_lock(&entity->queue_lock); added = kfifo_in(&entity->job_queue, &sched_job, sizeof(sched_job)) == sizeof(sched_job); if (added && kfifo_len(&entity->job_queue) == sizeof(sched_job)) first = true; spin_unlock(&entity->queue_lock); /* first job wakes up scheduler */ if (first) { /* Add the entity to the run queue */ + spin_lock(&entity->rq_lock); amd_sched_rq_add_entity(entity->rq, entity); + spin_unlock(&entity->rq_lock); amd_sched_wakeup(sched); } return added; } /* job_finish is called after hw fence signaled, and * the job had already been deleted from ring_mirror_list */ static void amd_sched_job_finish(struct work_struct *work) { struct amd_sched_job *s_job = container_of(work, struct amd_sched_job, finish_work); struct amd_gpu_scheduler *sched = s_job->sched; /* remove job from ring_mirror_list */ diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index b9283b5..51d626d 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -27,33 +27,35 @@ #include <linux/kfifo.h> #include <linux/dma-fence.h> struct amd_gpu_scheduler; struct amd_sched_rq; struct amd_sched_priority_ctr; /** * A scheduler entity is a wrapper around a job queue or a group * of other entities. Entities take turns emitting jobs from their * job queues to corresponding hardware ring based on scheduling * policy. */ struct amd_sched_entity { struct list_head list; - struct amd_sched_rq *rq; struct amd_gpu_scheduler *sched; + spinlock_t rq_lock; + struct amd_sched_rq *rq; + spinlock_t queue_lock; struct kfifo job_queue; atomic_t fence_seq; uint64_t fence_context; struct dma_fence *dependency; struct dma_fence_cb cb; }; /** * Run queue is a set of entities scheduling command submissions for * one specific ring. It implements the scheduling policy that selects * the next entity to emit commands from. */ @@ -154,30 +156,32 @@ struct amd_gpu_scheduler { spinlock_t job_list_lock; }; int amd_sched_init(struct amd_gpu_scheduler *sched, const struct amd_sched_backend_ops *ops, uint32_t hw_submission, long timeout, const char *name); void amd_sched_fini(struct amd_gpu_scheduler *sched); int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity, struct amd_sched_rq *rq, uint32_t jobs); void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity); void amd_sched_entity_push_job(struct amd_sched_job *sched_job); +void amd_sched_entity_set_rq(struct amd_sched_entity *entity, + struct amd_sched_rq *rq); int amd_sched_fence_slab_init(void); void amd_sched_fence_slab_fini(void); struct amd_sched_fence *amd_sched_fence_create( struct amd_sched_entity *s_entity, void *owner); void amd_sched_fence_scheduled(struct amd_sched_fence *fence); void amd_sched_fence_finished(struct amd_sched_fence *fence); int amd_sched_job_init(struct amd_sched_job *job, struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity, void *owner); void amd_sched_hw_job_reset(struct amd_gpu_scheduler *sched); void amd_sched_job_recovery(struct amd_gpu_scheduler *sched); bool amd_sched_dependency_optimized(struct dma_fence* fence, -- 2.9.3