[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