diff options
Diffstat (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c')
| -rw-r--r-- | drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 52 | 
1 files changed, 50 insertions, 2 deletions
| diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 3697eeeecf82..89619a5a4289 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -222,6 +222,12 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity)  	while ((entity->dependency = sched->ops->dependency(sched_job))) { +		if (entity->dependency->context == entity->fence_context) { +			/* We can ignore fences from ourself */ +			fence_put(entity->dependency); +			continue; +		} +  		if (fence_add_callback(entity->dependency, &entity->cb,  				       amd_sched_entity_wakeup))  			fence_put(entity->dependency); @@ -327,19 +333,49 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)  	struct amd_sched_fence *s_fence =  		container_of(cb, struct amd_sched_fence, cb);  	struct amd_gpu_scheduler *sched = s_fence->sched; +	unsigned long flags;  	atomic_dec(&sched->hw_rq_count);  	amd_sched_fence_signal(s_fence); +	if (sched->timeout != MAX_SCHEDULE_TIMEOUT) { +		cancel_delayed_work(&s_fence->dwork); +		spin_lock_irqsave(&sched->fence_list_lock, flags); +		list_del_init(&s_fence->list); +		spin_unlock_irqrestore(&sched->fence_list_lock, flags); +	}  	fence_put(&s_fence->base);  	wake_up_interruptible(&sched->wake_up_worker);  } +static void amd_sched_fence_work_func(struct work_struct *work) +{ +	struct amd_sched_fence *s_fence = +		container_of(work, struct amd_sched_fence, dwork.work); +	struct amd_gpu_scheduler *sched = s_fence->sched; +	struct amd_sched_fence *entity, *tmp; +	unsigned long flags; + +	DRM_ERROR("[%s] scheduler is timeout!\n", sched->name); + +	/* Clean all pending fences */ +	spin_lock_irqsave(&sched->fence_list_lock, flags); +	list_for_each_entry_safe(entity, tmp, &sched->fence_list, list) { +		DRM_ERROR("  fence no %d\n", entity->base.seqno); +		cancel_delayed_work(&entity->dwork); +		list_del_init(&entity->list); +		fence_put(&entity->base); +	} +	spin_unlock_irqrestore(&sched->fence_list_lock, flags); +} +  static int amd_sched_main(void *param)  {  	struct sched_param sparam = {.sched_priority = 1};  	struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param;  	int r, count; +	spin_lock_init(&sched->fence_list_lock); +	INIT_LIST_HEAD(&sched->fence_list);  	sched_setscheduler(current, SCHED_FIFO, &sparam);  	while (!kthread_should_stop()) { @@ -347,6 +383,7 @@ static int amd_sched_main(void *param)  		struct amd_sched_fence *s_fence;  		struct amd_sched_job *sched_job;  		struct fence *fence; +		unsigned long flags;  		wait_event_interruptible(sched->wake_up_worker,  			kthread_should_stop() || @@ -357,6 +394,15 @@ static int amd_sched_main(void *param)  		entity = sched_job->s_entity;  		s_fence = sched_job->s_fence; + +		if (sched->timeout != MAX_SCHEDULE_TIMEOUT) { +			INIT_DELAYED_WORK(&s_fence->dwork, amd_sched_fence_work_func); +			schedule_delayed_work(&s_fence->dwork, sched->timeout); +			spin_lock_irqsave(&sched->fence_list_lock, flags); +			list_add_tail(&s_fence->list, &sched->fence_list); +			spin_unlock_irqrestore(&sched->fence_list_lock, flags); +		} +  		atomic_inc(&sched->hw_rq_count);  		fence = sched->ops->run_job(sched_job);  		if (fence) { @@ -392,11 +438,12 @@ static int amd_sched_main(void *param)  */  int amd_sched_init(struct amd_gpu_scheduler *sched,  		   struct amd_sched_backend_ops *ops, -		   unsigned hw_submission, const char *name) +		   unsigned hw_submission, long timeout, const char *name)  {  	sched->ops = ops;  	sched->hw_submission_limit = hw_submission;  	sched->name = name; +	sched->timeout = timeout;  	amd_sched_rq_init(&sched->sched_rq);  	amd_sched_rq_init(&sched->kernel_rq); @@ -421,5 +468,6 @@ int amd_sched_init(struct amd_gpu_scheduler *sched,   */  void amd_sched_fini(struct amd_gpu_scheduler *sched)  { -	kthread_stop(sched->thread); +	if (sched->thread) +		kthread_stop(sched->thread);  } |