From bb977d3711ed1de1601b463e7fd5a43d82a2b077 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Tue, 18 Aug 2015 15:16:40 +0800 Subject: drm/amdgpu: abstract amdgpu_job for scheduler Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 42 ++++++++++----------------- 1 file changed, 15 insertions(+), 27 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 265d3e2f63cc..462c1617d56e 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -282,30 +282,18 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, * scheduler consum some queued command. * -1 other fail. */ -int amd_sched_push_job(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *c_entity, - void *data, - struct amd_sched_fence **fence) +int amd_sched_push_job(struct amd_sched_job *sched_job) { - struct amd_sched_job *job; - + struct amd_sched_fence *fence = + amd_sched_fence_create(sched_job->s_entity); if (!fence) return -EINVAL; - job = kzalloc(sizeof(struct amd_sched_job), GFP_KERNEL); - if (!job) - return -ENOMEM; - job->sched = sched; - job->s_entity = c_entity; - job->data = data; - *fence = amd_sched_fence_create(c_entity); - if ((*fence) == NULL) { - kfree(job); - return -EINVAL; - } - fence_get(&(*fence)->base); - job->s_fence = *fence; - while (kfifo_in_spinlocked(&c_entity->job_queue, &job, sizeof(void *), - &c_entity->queue_lock) != sizeof(void *)) { + fence_get(&fence->base); + sched_job->s_fence = fence; + while (kfifo_in_spinlocked(&sched_job->s_entity->job_queue, + &sched_job, sizeof(void *), + &sched_job->s_entity->queue_lock) != + sizeof(void *)) { /** * Current context used up all its IB slots * wait here, or need to check whether GPU is hung @@ -313,8 +301,8 @@ int amd_sched_push_job(struct amd_gpu_scheduler *sched, schedule(); } /* first job wake up scheduler */ - if ((kfifo_len(&c_entity->job_queue) / sizeof(void *)) == 1) - wake_up_interruptible(&sched->wait_queue); + if ((kfifo_len(&sched_job->s_entity->job_queue) / sizeof(void *)) == 1) + wake_up_interruptible(&sched_job->sched->wait_queue); return 0; } @@ -333,10 +321,8 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) list_del(&sched_job->list); atomic64_dec(&sched->hw_rq_count); spin_unlock_irqrestore(&sched->queue_lock, flags); - - sched->ops->process_job(sched, sched_job); fence_put(&sched_job->s_fence->base); - kfree(sched_job); + sched->ops->process_job(sched, sched_job); wake_up_interruptible(&sched->wait_queue); } @@ -359,7 +345,9 @@ static int amd_sched_main(void *param) r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) continue; - r = sched->ops->prepare_job(sched, c_entity, job); + r = 0; + if (sched->ops->prepare_job) + r = sched->ops->prepare_job(sched, c_entity, job); if (!r) { unsigned long flags; spin_lock_irqsave(&sched->queue_lock, flags); -- cgit From 2b184d8dbc002d3ef26e4827dd5a80d57533dcae Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 18 Aug 2015 14:41:25 +0200 Subject: drm/amdgpu: use a spinlock instead of a mutex for the rq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More appropriate and fixes some nasty lockdep warnings. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 49 ++++++++++----------------- 1 file changed, 17 insertions(+), 32 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 462c1617d56e..1125aa2e2a9a 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -30,27 +30,27 @@ /* Initialize a given run queue struct */ static void amd_sched_rq_init(struct amd_sched_rq *rq) { + spin_lock_init(&rq->lock); INIT_LIST_HEAD(&rq->entities); - mutex_init(&rq->lock); rq->current_entity = NULL; } static void amd_sched_rq_add_entity(struct amd_sched_rq *rq, struct amd_sched_entity *entity) { - mutex_lock(&rq->lock); + spin_lock(&rq->lock); list_add_tail(&entity->list, &rq->entities); - mutex_unlock(&rq->lock); + spin_unlock(&rq->lock); } static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq, struct amd_sched_entity *entity) { - mutex_lock(&rq->lock); + spin_lock(&rq->lock); list_del_init(&entity->list); if (rq->current_entity == entity) rq->current_entity = NULL; - mutex_unlock(&rq->lock); + spin_unlock(&rq->lock); } /** @@ -61,12 +61,16 @@ static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq, static struct amd_sched_entity * amd_sched_rq_select_entity(struct amd_sched_rq *rq) { - struct amd_sched_entity *entity = rq->current_entity; + struct amd_sched_entity *entity; + spin_lock(&rq->lock); + + entity = rq->current_entity; if (entity) { list_for_each_entry_continue(entity, &rq->entities, list) { if (!kfifo_is_empty(&entity->job_queue)) { rq->current_entity = entity; + spin_unlock(&rq->lock); return rq->current_entity; } } @@ -76,6 +80,7 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) if (!kfifo_is_empty(&entity->job_queue)) { rq->current_entity = entity; + spin_unlock(&rq->lock); return rq->current_entity; } @@ -83,6 +88,8 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) break; } + spin_unlock(&rq->lock); + return NULL; } @@ -108,22 +115,6 @@ static bool is_scheduler_ready(struct amd_gpu_scheduler *sched) return full; } -/** - * Select next entity from the kernel run queue, if not available, - * return null. -*/ -static struct amd_sched_entity * -kernel_rq_select_context(struct amd_gpu_scheduler *sched) -{ - struct amd_sched_entity *sched_entity; - struct amd_sched_rq *rq = &sched->kernel_rq; - - mutex_lock(&rq->lock); - sched_entity = amd_sched_rq_select_entity(rq); - mutex_unlock(&rq->lock); - return sched_entity; -} - /** * Select next entity containing real IB submissions */ @@ -132,21 +123,15 @@ select_context(struct amd_gpu_scheduler *sched) { struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; - struct amd_sched_rq *rq; if (!is_scheduler_ready(sched)) return NULL; /* Kernel run queue has higher priority than normal run queue*/ - tmp = kernel_rq_select_context(sched); - if (tmp != NULL) - goto exit; - - rq = &sched->sched_rq; - mutex_lock(&rq->lock); - tmp = amd_sched_rq_select_entity(rq); - mutex_unlock(&rq->lock); -exit: + tmp = amd_sched_rq_select_entity(&sched->kernel_rq); + if (tmp == NULL) + tmp = amd_sched_rq_select_entity(&sched->sched_rq); + if (sched->current_entity && (sched->current_entity != tmp)) wake_entity = sched->current_entity; sched->current_entity = tmp; -- cgit From ce882e6dc241ab8dded0eeeb33a86482d44a5689 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 19 Aug 2015 15:00:55 +0200 Subject: drm/amdgpu: remove v_seq handling from the scheduler v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simply not used any more. Only keep 32bit atomic for fence sequence numbering. v2: trivial rebase Signed-off-by: Christian König Reviewed-by: Alex Deucher (v1) Reviewed-by: Jammy Zhou (v1) Reviewed-by: Chunming Zhou (v1) --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 1125aa2e2a9a..f8d46b0b4e3b 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -156,14 +156,12 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_rq *rq, uint32_t jobs) { - uint64_t seq_ring = 0; char name[20]; if (!(sched && entity && rq)) return -EINVAL; memset(entity, 0, sizeof(struct amd_sched_entity)); - seq_ring = ((uint64_t)sched->ring_id) << 60; spin_lock_init(&entity->lock); entity->belongto_rq = rq; entity->scheduler = sched; @@ -179,8 +177,7 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, return -EINVAL; spin_lock_init(&entity->queue_lock); - atomic64_set(&entity->last_queued_v_seq, seq_ring); - atomic64_set(&entity->last_signaled_v_seq, seq_ring); + atomic_set(&entity->fence_seq, 0); /* Add the entity to the run queue */ amd_sched_rq_add_entity(rq, entity); @@ -299,8 +296,6 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) unsigned long flags; sched = sched_job->sched; - atomic64_set(&sched_job->s_entity->last_signaled_v_seq, - sched_job->s_fence->v_seq); amd_sched_fence_signal(sched_job->s_fence); spin_lock_irqsave(&sched->queue_lock, flags); list_del(&sched_job->list); @@ -421,15 +416,3 @@ int amd_sched_destroy(struct amd_gpu_scheduler *sched) kfree(sched); return 0; } - -/** - * Get next queued sequence number - * - * @entity The context entity - * - * return the next queued sequence number -*/ -uint64_t amd_sched_next_queued_seq(struct amd_sched_entity *c_entity) -{ - return atomic64_read(&c_entity->last_queued_v_seq) + 1; -} -- cgit From c746ba222363d2e0b0316b1c0bda21e2646b66f2 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 19 Aug 2015 16:12:15 +0200 Subject: drm/amdgpu: rework scheduler submission handling. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove active_hw_rq and it's protecting queue_lock, they are unused. User 32bit atomic for hw_rq_count, 64bits for counting to three is a bit overkill. Cleanup the function name and remove incorrect comments. Signed-off-by: Christian König Reviewed-by: Alex Deucher Reviewed-by: Jammy Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 43 +++++++-------------------- 1 file changed, 10 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index f8d46b0b4e3b..981420ea1cb5 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -94,25 +94,12 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) } /** - * Note: This function should only been called inside scheduler main - * function for thread safety, there is no other protection here. - * return ture if scheduler has something ready to run. - * - * For active_hw_rq, there is only one producer(scheduler thread) and - * one consumer(ISR). It should be safe to use this function in scheduler - * main thread to decide whether to continue emit more IBs. -*/ -static bool is_scheduler_ready(struct amd_gpu_scheduler *sched) + * Return ture if we can push more jobs to the hw. + */ +static bool amd_sched_ready(struct amd_gpu_scheduler *sched) { - unsigned long flags; - bool full; - - spin_lock_irqsave(&sched->queue_lock, flags); - full = atomic64_read(&sched->hw_rq_count) < - sched->hw_submission_limit ? true : false; - spin_unlock_irqrestore(&sched->queue_lock, flags); - - return full; + return atomic_read(&sched->hw_rq_count) < + sched->hw_submission_limit; } /** @@ -124,7 +111,7 @@ select_context(struct amd_gpu_scheduler *sched) struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; - if (!is_scheduler_ready(sched)) + if (!amd_sched_ready(sched)) return NULL; /* Kernel run queue has higher priority than normal run queue*/ @@ -293,14 +280,10 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) struct amd_sched_job *sched_job = container_of(cb, struct amd_sched_job, cb); struct amd_gpu_scheduler *sched; - unsigned long flags; sched = sched_job->sched; amd_sched_fence_signal(sched_job->s_fence); - spin_lock_irqsave(&sched->queue_lock, flags); - list_del(&sched_job->list); - atomic64_dec(&sched->hw_rq_count); - spin_unlock_irqrestore(&sched->queue_lock, flags); + atomic_dec(&sched->hw_rq_count); fence_put(&sched_job->s_fence->base); sched->ops->process_job(sched, sched_job); wake_up_interruptible(&sched->wait_queue); @@ -320,7 +303,7 @@ static int amd_sched_main(void *param) struct fence *fence; wait_event_interruptible(sched->wait_queue, - is_scheduler_ready(sched) && + amd_sched_ready(sched) && (c_entity = select_context(sched))); r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) @@ -329,11 +312,7 @@ static int amd_sched_main(void *param) if (sched->ops->prepare_job) r = sched->ops->prepare_job(sched, c_entity, job); if (!r) { - unsigned long flags; - spin_lock_irqsave(&sched->queue_lock, flags); - list_add_tail(&job->list, &sched->active_hw_rq); - atomic64_inc(&sched->hw_rq_count); - spin_unlock_irqrestore(&sched->queue_lock, flags); + atomic_inc(&sched->hw_rq_count); } mutex_lock(&sched->sched_lock); fence = sched->ops->run_job(sched, c_entity, job); @@ -384,13 +363,11 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, sched->hw_submission_limit = hw_submission; snprintf(name, sizeof(name), "gpu_sched[%d]", ring); mutex_init(&sched->sched_lock); - spin_lock_init(&sched->queue_lock); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); init_waitqueue_head(&sched->wait_queue); - INIT_LIST_HEAD(&sched->active_hw_rq); - atomic64_set(&sched->hw_rq_count, 0); + atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ sched->thread = kthread_create(amd_sched_main, sched, name); if (sched->thread) { -- cgit From 9788ec40322ef40d64f6d4276248f40666dc4505 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 19 Aug 2015 17:34:20 +0200 Subject: drm/amdgpu: remove some more unused entity members v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit None of them are used any more. v2: fix type in error message Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 981420ea1cb5..599318d3df0d 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -149,11 +149,9 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, return -EINVAL; memset(entity, 0, sizeof(struct amd_sched_entity)); - spin_lock_init(&entity->lock); entity->belongto_rq = rq; entity->scheduler = sched; init_waitqueue_head(&entity->wait_queue); - init_waitqueue_head(&entity->wait_emit); entity->fence_context = fence_context_alloc(1); snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context); memcpy(entity->name, name, 20); @@ -228,12 +226,9 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS) ) ? 0 : -1; - if (r) { - if (entity->is_pending) - DRM_INFO("Entity %p is in waiting state during fini,\ - all pending ibs will be canceled.\n", - entity); - } + if (r) + DRM_INFO("Entity %p is in waiting state during fini\n", + entity); amd_sched_rq_remove_entity(rq, entity); kfifo_free(&entity->job_queue); -- cgit From f85a6dd9ebd1bcaeb2f31cca71537e62606a23c2 Mon Sep 17 00:00:00 2001 From: Christian König Date: Wed, 19 Aug 2015 17:37:52 +0200 Subject: drm/amdgpu: cleanup entity picking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup function name, stop checking scheduler ready twice, but check if kernel thread should stop instead. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 599318d3df0d..2dd9c8aceba5 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -106,7 +106,7 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) * Select next entity containing real IB submissions */ static struct amd_sched_entity * -select_context(struct amd_gpu_scheduler *sched) +amd_sched_select_context(struct amd_gpu_scheduler *sched) { struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; @@ -286,20 +286,24 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) static int amd_sched_main(void *param) { - int r; - struct amd_sched_job *job; struct sched_param sparam = {.sched_priority = 1}; - struct amd_sched_entity *c_entity = NULL; struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param; + int r; sched_setscheduler(current, SCHED_FIFO, &sparam); while (!kthread_should_stop()) { + struct amd_sched_entity *c_entity = NULL; + struct amd_sched_job *job; struct fence *fence; wait_event_interruptible(sched->wait_queue, - amd_sched_ready(sched) && - (c_entity = select_context(sched))); + kthread_should_stop() || + (c_entity = amd_sched_select_context(sched))); + + if (!c_entity) + continue; + r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) continue; -- cgit From aef4852eed2841892796fb1e9abd7f8468384e62 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 14:47:46 +0200 Subject: drm/amdgpu: fix entity wakeup race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That actually didn't worked at all. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 43 +++++++++++++-------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2dd9c8aceba5..0133697c127e 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -108,7 +108,6 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) static struct amd_sched_entity * amd_sched_select_context(struct amd_gpu_scheduler *sched) { - struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; if (!amd_sched_ready(sched)) @@ -119,11 +118,6 @@ amd_sched_select_context(struct amd_gpu_scheduler *sched) if (tmp == NULL) tmp = amd_sched_rq_select_entity(&sched->sched_rq); - if (sched->current_entity && (sched->current_entity != tmp)) - wake_entity = sched->current_entity; - sched->current_entity = tmp; - if (wake_entity && wake_entity->need_wakeup) - wake_up(&wake_entity->wait_queue); return tmp; } @@ -184,16 +178,17 @@ static bool is_context_entity_initialized(struct amd_gpu_scheduler *sched, entity->belongto_rq != NULL; } -static bool is_context_entity_idle(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity) +/** + * Check if entity is idle + * + * @entity The pointer to a valid scheduler entity + * + * Return true if entity don't has any unscheduled jobs. + */ +static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity) { - /** - * Idle means no pending IBs, and the entity is not - * currently being used. - */ - barrier(); - if ((sched->current_entity != entity) && - kfifo_is_empty(&entity->job_queue)) + rmb(); + if (kfifo_is_empty(&entity->job_queue)) return true; return false; @@ -210,8 +205,8 @@ static bool is_context_entity_idle(struct amd_gpu_scheduler *sched, int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity) { - int r = 0; struct amd_sched_rq *rq = entity->belongto_rq; + long r; if (!is_context_entity_initialized(sched, entity)) return 0; @@ -220,13 +215,11 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, * The client will not queue more IBs during this fini, consume existing * queued IBs */ - r = wait_event_timeout( - entity->wait_queue, - is_context_entity_idle(sched, entity), - msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS) - ) ? 0 : -1; + r = wait_event_timeout(entity->wait_queue, + amd_sched_entity_is_idle(entity), + msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS)); - if (r) + if (r <= 0) DRM_INFO("Entity %p is in waiting state during fini\n", entity); @@ -325,6 +318,12 @@ static int amd_sched_main(void *param) fence_put(fence); } mutex_unlock(&sched->sched_lock); + + if (c_entity->need_wakeup) { + c_entity->need_wakeup = false; + wake_up(&c_entity->wait_queue); + } + } return 0; } -- cgit From f49565982194d601f4f3a99892d0f3c765aec104 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 16:59:38 +0200 Subject: drm/amdgpu: fix scheduler thread creation error checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 0133697c127e..435d70499d3e 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -367,15 +367,14 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, init_waitqueue_head(&sched->wait_queue); atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ - sched->thread = kthread_create(amd_sched_main, sched, name); - if (sched->thread) { - wake_up_process(sched->thread); - return sched; + sched->thread = kthread_run(amd_sched_main, sched, name); + if (IS_ERR(sched->thread)) { + DRM_ERROR("Failed to create scheduler for id %d.\n", ring); + kfree(sched); + return NULL; } - DRM_ERROR("Failed to create scheduler for id %d.\n", ring); - kfree(sched); - return NULL; + return sched; } /** -- cgit From e688b728228b951f41175e3a7c0738708d045969 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 17:01:01 +0200 Subject: drm/amdgpu: reorder scheduler functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep run queue, entity and scheduler handling together. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 56 +++++++++++++-------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 435d70499d3e..5fb189ca7fbe 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -93,34 +93,6 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) return NULL; } -/** - * Return ture if we can push more jobs to the hw. - */ -static bool amd_sched_ready(struct amd_gpu_scheduler *sched) -{ - return atomic_read(&sched->hw_rq_count) < - sched->hw_submission_limit; -} - -/** - * Select next entity containing real IB submissions -*/ -static struct amd_sched_entity * -amd_sched_select_context(struct amd_gpu_scheduler *sched) -{ - struct amd_sched_entity *tmp; - - if (!amd_sched_ready(sched)) - return NULL; - - /* Kernel run queue has higher priority than normal run queue*/ - tmp = amd_sched_rq_select_entity(&sched->kernel_rq); - if (tmp == NULL) - tmp = amd_sched_rq_select_entity(&sched->sched_rq); - - return tmp; -} - /** * Init a context entity used by scheduler when submit to HW ring. * @@ -263,6 +235,34 @@ int amd_sched_push_job(struct amd_sched_job *sched_job) return 0; } +/** + * Return ture if we can push more jobs to the hw. + */ +static bool amd_sched_ready(struct amd_gpu_scheduler *sched) +{ + return atomic_read(&sched->hw_rq_count) < + sched->hw_submission_limit; +} + +/** + * Select next entity containing real IB submissions +*/ +static struct amd_sched_entity * +amd_sched_select_context(struct amd_gpu_scheduler *sched) +{ + struct amd_sched_entity *tmp; + + if (!amd_sched_ready(sched)) + return NULL; + + /* Kernel run queue has higher priority than normal run queue*/ + tmp = amd_sched_rq_select_entity(&sched->kernel_rq); + if (tmp == NULL) + tmp = amd_sched_rq_select_entity(&sched->sched_rq); + + return tmp; +} + static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) { struct amd_sched_job *sched_job = -- cgit From d54fdb94b2fd4c989d498f69e8bbf4189fde42ef Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 17:03:48 +0200 Subject: drm/amdgpu: cleanup a scheduler function name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 5fb189ca7fbe..37badd6292cb 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -143,8 +143,8 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, * * return true if entity is initialized, false otherwise */ -static bool is_context_entity_initialized(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity) +static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched, + struct amd_sched_entity *entity) { return entity->scheduler == sched && entity->belongto_rq != NULL; @@ -180,7 +180,7 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_rq *rq = entity->belongto_rq; long r; - if (!is_context_entity_initialized(sched, entity)) + if (!amd_sched_entity_is_initialized(sched, entity)) return 0; entity->need_wakeup = true; /** -- cgit From b034b572f2823122d56cd0d235158873f84c7c23 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 17:08:25 +0200 Subject: drm/amdgpu: remove prepare_job callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not used any more. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 37badd6292cb..2ab63d223891 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -300,12 +300,8 @@ static int amd_sched_main(void *param) r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) continue; - r = 0; - if (sched->ops->prepare_job) - r = sched->ops->prepare_job(sched, c_entity, job); - if (!r) { - atomic_inc(&sched->hw_rq_count); - } + atomic_inc(&sched->hw_rq_count); + mutex_lock(&sched->sched_lock); fence = sched->ops->run_job(sched, c_entity, job); if (fence) { -- cgit From 1fca766b24d07e2daed1da0f224f5f395c73e32b Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 17:09:54 +0200 Subject: drm/amdgpu: remove sched_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It isn't protecting anything. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2ab63d223891..b13642f1e00b 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -302,7 +302,6 @@ static int amd_sched_main(void *param) continue; atomic_inc(&sched->hw_rq_count); - mutex_lock(&sched->sched_lock); fence = sched->ops->run_job(sched, c_entity, job); if (fence) { r = fence_add_callback(fence, &job->cb, @@ -313,7 +312,6 @@ static int amd_sched_main(void *param) DRM_ERROR("fence add callback failed (%d)\n", r); fence_put(fence); } - mutex_unlock(&sched->sched_lock); if (c_entity->need_wakeup) { c_entity->need_wakeup = false; @@ -356,7 +354,6 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, sched->preemption = preemption; sched->hw_submission_limit = hw_submission; snprintf(name, sizeof(name), "gpu_sched[%d]", ring); - mutex_init(&sched->sched_lock); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); -- cgit From 69f7dd652c08bffb267f418ded7b358e74783045 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 17:24:40 +0200 Subject: drm/amdgpu: remove unused parameters to amd_sched_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index b13642f1e00b..acae85572399 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -325,20 +325,14 @@ static int amd_sched_main(void *param) /** * Create a gpu scheduler * - * @device The device context for this scheduler - * @ops The backend operations for this scheduler. - * @id The scheduler is per ring, here is ring id. - * @granularity The minumum ms unit the scheduler will scheduled. - * @preemption Indicate whether this ring support preemption, 0 is no. + * @ops The backend operations for this scheduler. + * @ring The the ring id for the scheduler. + * @hw_submissions Number of hw submissions to do. * - * return the pointer to scheduler for success, otherwise return NULL + * Return the pointer to scheduler for success, otherwise return NULL */ -struct amd_gpu_scheduler *amd_sched_create(void *device, - struct amd_sched_backend_ops *ops, - unsigned ring, - unsigned granularity, - unsigned preemption, - unsigned hw_submission) +struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, + unsigned ring, unsigned hw_submission) { struct amd_gpu_scheduler *sched; char name[20]; @@ -347,11 +341,8 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, if (!sched) return NULL; - sched->device = device; sched->ops = ops; - sched->granularity = granularity; sched->ring_id = ring; - sched->preemption = preemption; sched->hw_submission_limit = hw_submission; snprintf(name, sizeof(name), "gpu_sched[%d]", ring); amd_sched_rq_init(&sched->sched_rq); -- cgit From 6c859274f363be9dc13f8849bdc59bb64f922f26 Mon Sep 17 00:00:00 2001 From: Christian König Date: Thu, 20 Aug 2015 16:12:50 +0200 Subject: drm/amdgpu: fix and cleanup amd_sched_entity_push_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling schedule() is probably the worse things we can do. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 78 +++++++++++++++------------ 1 file changed, 45 insertions(+), 33 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index acae85572399..29c45ed7d02f 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -121,7 +121,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, entity->fence_context = fence_context_alloc(1); snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context); memcpy(entity->name, name, 20); - entity->need_wakeup = false; if(kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL)) @@ -182,7 +181,7 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, if (!amd_sched_entity_is_initialized(sched, entity)) return 0; - entity->need_wakeup = true; + /** * The client will not queue more IBs during this fini, consume existing * queued IBs @@ -201,38 +200,55 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, } /** - * Submit a normal job to the job queue + * Helper to submit a job to the job queue * - * @sched The pointer to the scheduler - * @c_entity The pointer to amd_sched_entity * @job The pointer to job required to submit - * return 0 if succeed. -1 if failed. - * -2 indicate queue is full for this client, client should wait untill - * scheduler consum some queued command. - * -1 other fail. -*/ -int amd_sched_push_job(struct amd_sched_job *sched_job) + * + * Returns true if we could submit the job. + */ +static bool amd_sched_entity_in(struct amd_sched_job *job) +{ + struct amd_sched_entity *entity = job->s_entity; + bool added, first = false; + + spin_lock(&entity->queue_lock); + added = kfifo_in(&entity->job_queue, &job, sizeof(job)) == sizeof(job); + + if (added && kfifo_len(&entity->job_queue) == sizeof(job)) + first = true; + + spin_unlock(&entity->queue_lock); + + /* first job wakes up scheduler */ + if (first) + wake_up_interruptible(&job->sched->wait_queue); + + return added; +} + +/** + * Submit a job to the job queue + * + * @job The pointer to job required to submit + * + * Returns 0 for success, negative error code otherwise. + */ +int amd_sched_entity_push_job(struct amd_sched_job *sched_job) { - struct amd_sched_fence *fence = - amd_sched_fence_create(sched_job->s_entity); + struct amd_sched_entity *entity = sched_job->s_entity; + struct amd_sched_fence *fence = amd_sched_fence_create(entity); + int r; + if (!fence) - return -EINVAL; + return -ENOMEM; + fence_get(&fence->base); sched_job->s_fence = fence; - while (kfifo_in_spinlocked(&sched_job->s_entity->job_queue, - &sched_job, sizeof(void *), - &sched_job->s_entity->queue_lock) != - sizeof(void *)) { - /** - * Current context used up all its IB slots - * wait here, or need to check whether GPU is hung - */ - schedule(); - } - /* first job wake up scheduler */ - if ((kfifo_len(&sched_job->s_entity->job_queue) / sizeof(void *)) == 1) - wake_up_interruptible(&sched_job->sched->wait_queue); - return 0; + + r = wait_event_interruptible(entity->wait_queue, + amd_sched_entity_in(sched_job)); + + return r; } /** @@ -313,11 +329,7 @@ static int amd_sched_main(void *param) fence_put(fence); } - if (c_entity->need_wakeup) { - c_entity->need_wakeup = false; - wake_up(&c_entity->wait_queue); - } - + wake_up(&c_entity->wait_queue); } return 0; } -- cgit From c14692f0a728a9d79fb03c7ce521eb07ec0e2b23 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 21 Aug 2015 15:18:47 +0200 Subject: drm/amdgpu: remove entity reference from sched fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entity don't live as long as scheduler fences. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 29c45ed7d02f..d747f82808a7 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -109,8 +109,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_rq *rq, uint32_t jobs) { - char name[20]; - if (!(sched && entity && rq)) return -EINVAL; @@ -119,8 +117,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, entity->scheduler = sched; init_waitqueue_head(&entity->wait_queue); entity->fence_context = fence_context_alloc(1); - snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context); - memcpy(entity->name, name, 20); if(kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL)) @@ -347,7 +343,6 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, unsigned ring, unsigned hw_submission) { struct amd_gpu_scheduler *sched; - char name[20]; sched = kzalloc(sizeof(struct amd_gpu_scheduler), GFP_KERNEL); if (!sched) @@ -356,14 +351,14 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, sched->ops = ops; sched->ring_id = ring; sched->hw_submission_limit = hw_submission; - snprintf(name, sizeof(name), "gpu_sched[%d]", ring); + snprintf(sched->name, sizeof(sched->name), "amdgpu[%d]", ring); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); init_waitqueue_head(&sched->wait_queue); atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ - sched->thread = kthread_run(amd_sched_main, sched, name); + sched->thread = kthread_run(amd_sched_main, sched, sched->name); if (IS_ERR(sched->thread)) { DRM_ERROR("Failed to create scheduler for id %d.\n", ring); kfree(sched); -- cgit From 84f76ea6b03a766931e5d6d650af5ab980c6c4f4 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 24 Aug 2015 12:47:36 +0800 Subject: drm/amdgpu: add owner for sched fence Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index d747f82808a7..24593fd29150 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -232,7 +232,8 @@ static bool amd_sched_entity_in(struct amd_sched_job *job) int amd_sched_entity_push_job(struct amd_sched_job *sched_job) { struct amd_sched_entity *entity = sched_job->s_entity; - struct amd_sched_fence *fence = amd_sched_fence_create(entity); + struct amd_sched_fence *fence = amd_sched_fence_create( + entity, sched_job->owner); int r; if (!fence) -- cgit From f38fdfddfaab070e3ff2333a79e45169ee33dc28 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 24 Aug 2015 11:35:26 +0800 Subject: drm/amdgpu: add priv data to sched Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 24593fd29150..2df6f174ba7b 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -341,7 +341,8 @@ static int amd_sched_main(void *param) * Return the pointer to scheduler for success, otherwise return NULL */ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, - unsigned ring, unsigned hw_submission) + unsigned ring, unsigned hw_submission, + void *priv) { struct amd_gpu_scheduler *sched; @@ -352,6 +353,7 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, sched->ops = ops; sched->ring_id = ring; sched->hw_submission_limit = hw_submission; + sched->priv = priv; snprintf(sched->name, sizeof(sched->name), "amdgpu[%d]", ring); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); -- cgit From 062c7fb3ebb42d2a50d4644b3e49e731361e6951 Mon Sep 17 00:00:00 2001 From: Christian König Date: Fri, 21 Aug 2015 15:46:43 +0200 Subject: drm/amdgpu: remove entity idle timeout v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing the entity from scheduling can deadlock the whole system. Wait forever till the remaining IBs are scheduled. v2: fix comment as well Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou (v1) --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2df6f174ba7b..ca22d9032477 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -167,32 +167,24 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity) * @sched Pointer to scheduler instance * @entity The pointer to a valid scheduler entity * - * return 0 if succeed. negative error code on failure + * Cleanup and free the allocated resources. */ -int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity) +void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, + struct amd_sched_entity *entity) { struct amd_sched_rq *rq = entity->belongto_rq; - long r; if (!amd_sched_entity_is_initialized(sched, entity)) - return 0; + return; /** * The client will not queue more IBs during this fini, consume existing * queued IBs */ - r = wait_event_timeout(entity->wait_queue, - amd_sched_entity_is_idle(entity), - msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS)); - - if (r <= 0) - DRM_INFO("Entity %p is in waiting state during fini\n", - entity); + wait_event(entity->wait_queue, amd_sched_entity_is_idle(entity)); amd_sched_rq_remove_entity(rq, entity); kfifo_free(&entity->job_queue); - return r; } /** -- cgit From 88079006dc412c5d1676f9f6e9c4d72a209eb556 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 24 Aug 2015 14:29:40 +0200 Subject: drm/amdgpu: wake up scheduler only when neccessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index ca22d9032477..414536557673 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -27,6 +27,8 @@ #include #include "gpu_scheduler.h" +static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); + /* Initialize a given run queue struct */ static void amd_sched_rq_init(struct amd_sched_rq *rq) { @@ -209,7 +211,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *job) /* first job wakes up scheduler */ if (first) - wake_up_interruptible(&job->sched->wait_queue); + amd_sched_wakeup(job->sched); return added; } @@ -249,6 +251,15 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) sched->hw_submission_limit; } +/** + * Wake up the scheduler when it is ready + */ +static void amd_sched_wakeup(struct amd_gpu_scheduler *sched) +{ + if (amd_sched_ready(sched)) + wake_up_interruptible(&sched->wait_queue); +} + /** * Select next entity containing real IB submissions */ -- cgit From bd755d08709f05a81104e8f81d721b5cc353a2b3 Mon Sep 17 00:00:00 2001 From: Christian König Date: Mon, 24 Aug 2015 14:57:26 +0200 Subject: drm/amdgpu: remove extra parameters from scheduler callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 414536557673..6dfbdea85e87 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -289,7 +289,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) amd_sched_fence_signal(sched_job->s_fence); atomic_dec(&sched->hw_rq_count); fence_put(&sched_job->s_fence->base); - sched->ops->process_job(sched, sched_job); + sched->ops->process_job(sched_job); wake_up_interruptible(&sched->wait_queue); } @@ -318,7 +318,7 @@ static int amd_sched_main(void *param) continue; atomic_inc(&sched->hw_rq_count); - fence = sched->ops->run_job(sched, c_entity, job); + fence = sched->ops->run_job(job); if (fence) { r = fence_add_callback(fence, &job->cb, amd_sched_process_job); -- cgit From c2b6bd7e91aad8440a2f55bdbde6f5a8ae19fac5 Mon Sep 17 00:00:00 2001 From: Christian König Date: Tue, 25 Aug 2015 21:39:31 +0200 Subject: drm/amdgpu: fix wait queue handling in the scheduler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Freeing up a queue after signalling it isn't race free. Signed-off-by: Christian König Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c') diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 6dfbdea85e87..d99fe90991dc 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -117,7 +117,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, memset(entity, 0, sizeof(struct amd_sched_entity)); entity->belongto_rq = rq; entity->scheduler = sched; - init_waitqueue_head(&entity->wait_queue); entity->fence_context = fence_context_alloc(1); if(kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), @@ -183,7 +182,7 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, * The client will not queue more IBs during this fini, consume existing * queued IBs */ - wait_event(entity->wait_queue, amd_sched_entity_is_idle(entity)); + wait_event(sched->job_scheduled, amd_sched_entity_is_idle(entity)); amd_sched_rq_remove_entity(rq, entity); kfifo_free(&entity->job_queue); @@ -236,7 +235,7 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job) fence_get(&fence->base); sched_job->s_fence = fence; - r = wait_event_interruptible(entity->wait_queue, + r = wait_event_interruptible(entity->scheduler->job_scheduled, amd_sched_entity_in(sched_job)); return r; @@ -257,7 +256,7 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) static void amd_sched_wakeup(struct amd_gpu_scheduler *sched) { if (amd_sched_ready(sched)) - wake_up_interruptible(&sched->wait_queue); + wake_up_interruptible(&sched->wake_up_worker); } /** @@ -290,7 +289,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) atomic_dec(&sched->hw_rq_count); fence_put(&sched_job->s_fence->base); sched->ops->process_job(sched_job); - wake_up_interruptible(&sched->wait_queue); + wake_up_interruptible(&sched->wake_up_worker); } static int amd_sched_main(void *param) @@ -306,7 +305,7 @@ static int amd_sched_main(void *param) struct amd_sched_job *job; struct fence *fence; - wait_event_interruptible(sched->wait_queue, + wait_event_interruptible(sched->wake_up_worker, kthread_should_stop() || (c_entity = amd_sched_select_context(sched))); @@ -329,7 +328,7 @@ static int amd_sched_main(void *param) fence_put(fence); } - wake_up(&c_entity->wait_queue); + wake_up(&sched->job_scheduled); } return 0; } @@ -361,7 +360,8 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); - init_waitqueue_head(&sched->wait_queue); + init_waitqueue_head(&sched->wake_up_worker); + init_waitqueue_head(&sched->job_scheduled); atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ sched->thread = kthread_run(amd_sched_main, sched, sched->name); -- cgit