[PATCH 6/8] drm/amd/sched: allow clients to edit an entity's rq
Christian König
deathsimple at vodafone.de
Fri Jun 9 10:58:54 UTC 2017
Am 09.06.2017 um 00:06 schrieb Andres Rodriguez:
> 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;
> +
Keep the order here, the "list" memory belongs to the rq member.
Apart from that the patch looks good to me,
Christian.
> 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,
More information about the amd-gfx
mailing list