aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd
diff options
context:
space:
mode:
authorAndrey Grodzovsky <Andrey.Grodzovsky@amd.com>2017-10-12 16:46:26 -0400
committerAlex Deucher <alexander.deucher@amd.com>2017-12-04 16:33:11 -0500
commit83f4b1180155f2d65472ce943a1f051215030560 (patch)
tree6e9a6740c8bb3f720ac65a480e5ec347c278d240 /drivers/gpu/drm/amd
parent27105db6c63a571b91d01e749d026105a1e63bcf (diff)
drm/amdgpu: Fix deadlock during GPU reset.
Bug: Kfifo is limited at size, during GPU reset it would fill up to limit and the pushing thread (producer) would wait for the scheduler worker to consume the items in the fifo while holding reservation lock on a BO. The gpu reset thread on the other hand blocks the scheduler during reset. Before it unblocks the sceduler it might want to recover VRAM and so will try to reserve the same BO the producer thread is already holding creating a deadlock. Fix: Switch from kfifo to SPSC queue which is unlimited in size. Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com> Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd')
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h4
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.c68
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.h4
3 files changed, 29 insertions, 47 deletions
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
index 283a0dc25e84..705380eb693c 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
+++ b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
@@ -29,8 +29,8 @@ TRACE_EVENT(amd_sched_job,
29 __entry->id = sched_job->id; 29 __entry->id = sched_job->id;
30 __entry->fence = &sched_job->s_fence->finished; 30 __entry->fence = &sched_job->s_fence->finished;
31 __entry->name = sched_job->sched->name; 31 __entry->name = sched_job->sched->name;
32 __entry->job_count = kfifo_len( 32 __entry->job_count = spsc_queue_count(
33 &sched_job->s_entity->job_queue) / sizeof(sched_job); 33 &sched_job->s_entity->job_queue);
34 __entry->hw_job_count = atomic_read( 34 __entry->hw_job_count = atomic_read(
35 &sched_job->sched->hw_rq_count); 35 &sched_job->sched->hw_rq_count);
36 ), 36 ),
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
index 1474866d9048..1a2267ce62a8 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
@@ -28,9 +28,14 @@
28#include <drm/drmP.h> 28#include <drm/drmP.h>
29#include "gpu_scheduler.h" 29#include "gpu_scheduler.h"
30 30
31#include "spsc_queue.h"
32
31#define CREATE_TRACE_POINTS 33#define CREATE_TRACE_POINTS
32#include "gpu_sched_trace.h" 34#include "gpu_sched_trace.h"
33 35
36#define to_amd_sched_job(sched_job) \
37 container_of((sched_job), struct amd_sched_job, queue_node)
38
34static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity); 39static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity);
35static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); 40static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);
36static void amd_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb); 41static void amd_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb);
@@ -123,8 +128,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
123 struct amd_sched_rq *rq, 128 struct amd_sched_rq *rq,
124 uint32_t jobs, atomic_t *guilty) 129 uint32_t jobs, atomic_t *guilty)
125{ 130{
126 int r;
127
128 if (!(sched && entity && rq)) 131 if (!(sched && entity && rq))
129 return -EINVAL; 132 return -EINVAL;
130 133
@@ -136,9 +139,7 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
136 139
137 spin_lock_init(&entity->rq_lock); 140 spin_lock_init(&entity->rq_lock);
138 spin_lock_init(&entity->queue_lock); 141 spin_lock_init(&entity->queue_lock);
139 r = kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL); 142 spsc_queue_init(&entity->job_queue);
140 if (r)
141 return r;
142 143
143 atomic_set(&entity->fence_seq, 0); 144 atomic_set(&entity->fence_seq, 0);
144 entity->fence_context = dma_fence_context_alloc(2); 145 entity->fence_context = dma_fence_context_alloc(2);
@@ -171,7 +172,7 @@ static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched,
171static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity) 172static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity)
172{ 173{
173 rmb(); 174 rmb();
174 if (kfifo_is_empty(&entity->job_queue)) 175 if (spsc_queue_peek(&entity->job_queue) == NULL)
175 return true; 176 return true;
176 177
177 return false; 178 return false;
@@ -186,7 +187,7 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity)
186 */ 187 */
187static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity) 188static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity)
188{ 189{
189 if (kfifo_is_empty(&entity->job_queue)) 190 if (spsc_queue_peek(&entity->job_queue) == NULL)
190 return false; 191 return false;
191 192
192 if (READ_ONCE(entity->dependency)) 193 if (READ_ONCE(entity->dependency))
@@ -228,7 +229,7 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
228 */ 229 */
229 kthread_park(sched->thread); 230 kthread_park(sched->thread);
230 kthread_unpark(sched->thread); 231 kthread_unpark(sched->thread);
231 while (kfifo_out(&entity->job_queue, &job, sizeof(job))) { 232 while ((job = to_amd_sched_job(spsc_queue_pop(&entity->job_queue)))) {
232 struct amd_sched_fence *s_fence = job->s_fence; 233 struct amd_sched_fence *s_fence = job->s_fence;
233 amd_sched_fence_scheduled(s_fence); 234 amd_sched_fence_scheduled(s_fence);
234 dma_fence_set_error(&s_fence->finished, -ESRCH); 235 dma_fence_set_error(&s_fence->finished, -ESRCH);
@@ -236,9 +237,7 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
236 dma_fence_put(&s_fence->finished); 237 dma_fence_put(&s_fence->finished);
237 sched->ops->free_job(job); 238 sched->ops->free_job(job);
238 } 239 }
239
240 } 240 }
241 kfifo_free(&entity->job_queue);
242} 241}
243 242
244static void amd_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb) 243static void amd_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb)
@@ -333,40 +332,41 @@ static bool amd_sched_entity_add_dependency_cb(struct amd_sched_entity *entity)
333} 332}
334 333
335static struct amd_sched_job * 334static struct amd_sched_job *
336amd_sched_entity_peek_job(struct amd_sched_entity *entity) 335amd_sched_entity_pop_job(struct amd_sched_entity *entity)
337{ 336{
338 struct amd_gpu_scheduler *sched = entity->sched; 337 struct amd_gpu_scheduler *sched = entity->sched;
339 struct amd_sched_job *sched_job; 338 struct amd_sched_job *sched_job = to_amd_sched_job(
339 spsc_queue_peek(&entity->job_queue));
340 340
341 if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job))) 341 if (!sched_job)
342 return NULL; 342 return NULL;
343 343
344 while ((entity->dependency = sched->ops->dependency(sched_job))) 344 while ((entity->dependency = sched->ops->dependency(sched_job)))
345 if (amd_sched_entity_add_dependency_cb(entity)) 345 if (amd_sched_entity_add_dependency_cb(entity))
346 return NULL; 346 return NULL;
347 347
348 sched_job->s_entity = NULL;
349 spsc_queue_pop(&entity->job_queue);
348 return sched_job; 350 return sched_job;
349} 351}
350 352
351/** 353/**
352 * Helper to submit a job to the job queue 354 * Submit a job to the job queue
353 * 355 *
354 * @sched_job The pointer to job required to submit 356 * @sched_job The pointer to job required to submit
355 * 357 *
356 * Returns true if we could submit the job. 358 * Returns 0 for success, negative error code otherwise.
357 */ 359 */
358static bool amd_sched_entity_in(struct amd_sched_job *sched_job) 360void amd_sched_entity_push_job(struct amd_sched_job *sched_job)
359{ 361{
360 struct amd_gpu_scheduler *sched = sched_job->sched; 362 struct amd_gpu_scheduler *sched = sched_job->sched;
361 struct amd_sched_entity *entity = sched_job->s_entity; 363 struct amd_sched_entity *entity = sched_job->s_entity;
362 bool added, first = false; 364 bool first = false;
363 365
364 spin_lock(&entity->queue_lock); 366 trace_amd_sched_job(sched_job);
365 added = kfifo_in(&entity->job_queue, &sched_job,
366 sizeof(sched_job)) == sizeof(sched_job);
367 367
368 if (added && kfifo_len(&entity->job_queue) == sizeof(sched_job)) 368 spin_lock(&entity->queue_lock);
369 first = true; 369 first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
370 370
371 spin_unlock(&entity->queue_lock); 371 spin_unlock(&entity->queue_lock);
372 372
@@ -378,7 +378,6 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
378 spin_unlock(&entity->rq_lock); 378 spin_unlock(&entity->rq_lock);
379 amd_sched_wakeup(sched); 379 amd_sched_wakeup(sched);
380 } 380 }
381 return added;
382} 381}
383 382
384/* job_finish is called after hw fence signaled 383/* job_finish is called after hw fence signaled
@@ -535,22 +534,6 @@ void amd_sched_job_recovery(struct amd_gpu_scheduler *sched)
535 spin_unlock(&sched->job_list_lock); 534 spin_unlock(&sched->job_list_lock);
536} 535}
537 536
538/**
539 * Submit a job to the job queue
540 *
541 * @sched_job The pointer to job required to submit
542 *
543 * Returns 0 for success, negative error code otherwise.
544 */
545void amd_sched_entity_push_job(struct amd_sched_job *sched_job)
546{
547 struct amd_sched_entity *entity = sched_job->s_entity;
548
549 trace_amd_sched_job(sched_job);
550 wait_event(entity->sched->job_scheduled,
551 amd_sched_entity_in(sched_job));
552}
553
554/* init a sched_job with basic field */ 537/* init a sched_job with basic field */
555int amd_sched_job_init(struct amd_sched_job *job, 538int amd_sched_job_init(struct amd_sched_job *job,
556 struct amd_gpu_scheduler *sched, 539 struct amd_gpu_scheduler *sched,
@@ -641,7 +624,7 @@ static int amd_sched_main(void *param)
641{ 624{
642 struct sched_param sparam = {.sched_priority = 1}; 625 struct sched_param sparam = {.sched_priority = 1};
643 struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param; 626 struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param;
644 int r, count; 627 int r;
645 628
646 sched_setscheduler(current, SCHED_FIFO, &sparam); 629 sched_setscheduler(current, SCHED_FIFO, &sparam);
647 630
@@ -659,7 +642,7 @@ static int amd_sched_main(void *param)
659 if (!entity) 642 if (!entity)
660 continue; 643 continue;
661 644
662 sched_job = amd_sched_entity_peek_job(entity); 645 sched_job = amd_sched_entity_pop_job(entity);
663 if (!sched_job) 646 if (!sched_job)
664 continue; 647 continue;
665 648
@@ -686,9 +669,6 @@ static int amd_sched_main(void *param)
686 amd_sched_process_job(NULL, &s_fence->cb); 669 amd_sched_process_job(NULL, &s_fence->cb);
687 } 670 }
688 671
689 count = kfifo_out(&entity->job_queue, &sched_job,
690 sizeof(sched_job));
691 WARN_ON(count != sizeof(sched_job));
692 wake_up(&sched->job_scheduled); 672 wake_up(&sched->job_scheduled);
693 } 673 }
694 return 0; 674 return 0;
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
index be75172587da..f9e3a83cddc6 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
@@ -26,6 +26,7 @@
26 26
27#include <linux/kfifo.h> 27#include <linux/kfifo.h>
28#include <linux/dma-fence.h> 28#include <linux/dma-fence.h>
29#include "spsc_queue.h"
29 30
30struct amd_gpu_scheduler; 31struct amd_gpu_scheduler;
31struct amd_sched_rq; 32struct amd_sched_rq;
@@ -56,7 +57,7 @@ struct amd_sched_entity {
56 struct amd_gpu_scheduler *sched; 57 struct amd_gpu_scheduler *sched;
57 58
58 spinlock_t queue_lock; 59 spinlock_t queue_lock;
59 struct kfifo job_queue; 60 struct spsc_queue job_queue;
60 61
61 atomic_t fence_seq; 62 atomic_t fence_seq;
62 uint64_t fence_context; 63 uint64_t fence_context;
@@ -88,6 +89,7 @@ struct amd_sched_fence {
88}; 89};
89 90
90struct amd_sched_job { 91struct amd_sched_job {
92 struct spsc_node queue_node;
91 struct amd_gpu_scheduler *sched; 93 struct amd_gpu_scheduler *sched;
92 struct amd_sched_entity *s_entity; 94 struct amd_sched_entity *s_entity;
93 struct amd_sched_fence *s_fence; 95 struct amd_sched_fence *s_fence;