]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blob - drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
Input: wm97xx: add new AC97 bus support
[mirror_ubuntu-focal-kernel.git] / drivers / gpu / drm / amd / scheduler / gpu_scheduler.c
1 /*
2 * Copyright 2015 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 *
23 */
24 #include <linux/kthread.h>
25 #include <linux/wait.h>
26 #include <linux/sched.h>
27 #include <uapi/linux/sched/types.h>
28 #include <drm/drmP.h>
29 #include "gpu_scheduler.h"
30
31 #define CREATE_TRACE_POINTS
32 #include "gpu_sched_trace.h"
33
34 static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity);
35 static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);
36 static void amd_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb);
37
38 /* Initialize a given run queue struct */
39 static void amd_sched_rq_init(struct amd_sched_rq *rq)
40 {
41 spin_lock_init(&rq->lock);
42 INIT_LIST_HEAD(&rq->entities);
43 rq->current_entity = NULL;
44 }
45
46 static void amd_sched_rq_add_entity(struct amd_sched_rq *rq,
47 struct amd_sched_entity *entity)
48 {
49 if (!list_empty(&entity->list))
50 return;
51 spin_lock(&rq->lock);
52 list_add_tail(&entity->list, &rq->entities);
53 spin_unlock(&rq->lock);
54 }
55
56 static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,
57 struct amd_sched_entity *entity)
58 {
59 if (list_empty(&entity->list))
60 return;
61 spin_lock(&rq->lock);
62 list_del_init(&entity->list);
63 if (rq->current_entity == entity)
64 rq->current_entity = NULL;
65 spin_unlock(&rq->lock);
66 }
67
68 /**
69 * Select an entity which could provide a job to run
70 *
71 * @rq The run queue to check.
72 *
73 * Try to find a ready entity, returns NULL if none found.
74 */
75 static struct amd_sched_entity *
76 amd_sched_rq_select_entity(struct amd_sched_rq *rq)
77 {
78 struct amd_sched_entity *entity;
79
80 spin_lock(&rq->lock);
81
82 entity = rq->current_entity;
83 if (entity) {
84 list_for_each_entry_continue(entity, &rq->entities, list) {
85 if (amd_sched_entity_is_ready(entity)) {
86 rq->current_entity = entity;
87 spin_unlock(&rq->lock);
88 return entity;
89 }
90 }
91 }
92
93 list_for_each_entry(entity, &rq->entities, list) {
94
95 if (amd_sched_entity_is_ready(entity)) {
96 rq->current_entity = entity;
97 spin_unlock(&rq->lock);
98 return entity;
99 }
100
101 if (entity == rq->current_entity)
102 break;
103 }
104
105 spin_unlock(&rq->lock);
106
107 return NULL;
108 }
109
110 /**
111 * Init a context entity used by scheduler when submit to HW ring.
112 *
113 * @sched The pointer to the scheduler
114 * @entity The pointer to a valid amd_sched_entity
115 * @rq The run queue this entity belongs
116 * @kernel If this is an entity for the kernel
117 * @jobs The max number of jobs in the job queue
118 *
119 * return 0 if succeed. negative error code on failure
120 */
121 int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
122 struct amd_sched_entity *entity,
123 struct amd_sched_rq *rq,
124 uint32_t jobs)
125 {
126 int r;
127
128 if (!(sched && entity && rq))
129 return -EINVAL;
130
131 memset(entity, 0, sizeof(struct amd_sched_entity));
132 INIT_LIST_HEAD(&entity->list);
133 entity->rq = rq;
134 entity->sched = sched;
135
136 spin_lock_init(&entity->queue_lock);
137 r = kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL);
138 if (r)
139 return r;
140
141 atomic_set(&entity->fence_seq, 0);
142 entity->fence_context = dma_fence_context_alloc(2);
143
144 return 0;
145 }
146
147 /**
148 * Query if entity is initialized
149 *
150 * @sched Pointer to scheduler instance
151 * @entity The pointer to a valid scheduler entity
152 *
153 * return true if entity is initialized, false otherwise
154 */
155 static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched,
156 struct amd_sched_entity *entity)
157 {
158 return entity->sched == sched &&
159 entity->rq != NULL;
160 }
161
162 /**
163 * Check if entity is idle
164 *
165 * @entity The pointer to a valid scheduler entity
166 *
167 * Return true if entity don't has any unscheduled jobs.
168 */
169 static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity)
170 {
171 rmb();
172 if (kfifo_is_empty(&entity->job_queue))
173 return true;
174
175 return false;
176 }
177
178 /**
179 * Check if entity is ready
180 *
181 * @entity The pointer to a valid scheduler entity
182 *
183 * Return true if entity could provide a job.
184 */
185 static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity)
186 {
187 if (kfifo_is_empty(&entity->job_queue))
188 return false;
189
190 if (ACCESS_ONCE(entity->dependency))
191 return false;
192
193 return true;
194 }
195
196 /**
197 * Destroy a context entity
198 *
199 * @sched Pointer to scheduler instance
200 * @entity The pointer to a valid scheduler entity
201 *
202 * Cleanup and free the allocated resources.
203 */
204 void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
205 struct amd_sched_entity *entity)
206 {
207 struct amd_sched_rq *rq = entity->rq;
208 int r;
209
210 if (!amd_sched_entity_is_initialized(sched, entity))
211 return;
212 /**
213 * The client will not queue more IBs during this fini, consume existing
214 * queued IBs or discard them on SIGKILL
215 */
216 if ((current->flags & PF_SIGNALED) && current->exit_code == SIGKILL)
217 r = -ERESTARTSYS;
218 else
219 r = wait_event_killable(sched->job_scheduled,
220 amd_sched_entity_is_idle(entity));
221 amd_sched_rq_remove_entity(rq, entity);
222 if (r) {
223 struct amd_sched_job *job;
224
225 /* Park the kernel for a moment to make sure it isn't processing
226 * our enity.
227 */
228 kthread_park(sched->thread);
229 kthread_unpark(sched->thread);
230 while (kfifo_out(&entity->job_queue, &job, sizeof(job)))
231 sched->ops->free_job(job);
232
233 }
234 kfifo_free(&entity->job_queue);
235 }
236
237 static void amd_sched_entity_wakeup(struct dma_fence *f, struct dma_fence_cb *cb)
238 {
239 struct amd_sched_entity *entity =
240 container_of(cb, struct amd_sched_entity, cb);
241 entity->dependency = NULL;
242 dma_fence_put(f);
243 amd_sched_wakeup(entity->sched);
244 }
245
246 static void amd_sched_entity_clear_dep(struct dma_fence *f, struct dma_fence_cb *cb)
247 {
248 struct amd_sched_entity *entity =
249 container_of(cb, struct amd_sched_entity, cb);
250 entity->dependency = NULL;
251 dma_fence_put(f);
252 }
253
254 bool amd_sched_dependency_optimized(struct dma_fence* fence,
255 struct amd_sched_entity *entity)
256 {
257 struct amd_gpu_scheduler *sched = entity->sched;
258 struct amd_sched_fence *s_fence;
259
260 if (!fence || dma_fence_is_signaled(fence))
261 return false;
262 if (fence->context == entity->fence_context)
263 return true;
264 s_fence = to_amd_sched_fence(fence);
265 if (s_fence && s_fence->sched == sched)
266 return true;
267
268 return false;
269 }
270
271 static bool amd_sched_entity_add_dependency_cb(struct amd_sched_entity *entity)
272 {
273 struct amd_gpu_scheduler *sched = entity->sched;
274 struct dma_fence * fence = entity->dependency;
275 struct amd_sched_fence *s_fence;
276
277 if (fence->context == entity->fence_context) {
278 /* We can ignore fences from ourself */
279 dma_fence_put(entity->dependency);
280 return false;
281 }
282
283 s_fence = to_amd_sched_fence(fence);
284 if (s_fence && s_fence->sched == sched) {
285
286 /*
287 * Fence is from the same scheduler, only need to wait for
288 * it to be scheduled
289 */
290 fence = dma_fence_get(&s_fence->scheduled);
291 dma_fence_put(entity->dependency);
292 entity->dependency = fence;
293 if (!dma_fence_add_callback(fence, &entity->cb,
294 amd_sched_entity_clear_dep))
295 return true;
296
297 /* Ignore it when it is already scheduled */
298 dma_fence_put(fence);
299 return false;
300 }
301
302 if (!dma_fence_add_callback(entity->dependency, &entity->cb,
303 amd_sched_entity_wakeup))
304 return true;
305
306 dma_fence_put(entity->dependency);
307 return false;
308 }
309
310 static struct amd_sched_job *
311 amd_sched_entity_pop_job(struct amd_sched_entity *entity)
312 {
313 struct amd_gpu_scheduler *sched = entity->sched;
314 struct amd_sched_job *sched_job;
315
316 if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job)))
317 return NULL;
318
319 while ((entity->dependency = sched->ops->dependency(sched_job)))
320 if (amd_sched_entity_add_dependency_cb(entity))
321 return NULL;
322
323 return sched_job;
324 }
325
326 /**
327 * Helper to submit a job to the job queue
328 *
329 * @sched_job The pointer to job required to submit
330 *
331 * Returns true if we could submit the job.
332 */
333 static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
334 {
335 struct amd_gpu_scheduler *sched = sched_job->sched;
336 struct amd_sched_entity *entity = sched_job->s_entity;
337 bool added, first = false;
338
339 spin_lock(&entity->queue_lock);
340 added = kfifo_in(&entity->job_queue, &sched_job,
341 sizeof(sched_job)) == sizeof(sched_job);
342
343 if (added && kfifo_len(&entity->job_queue) == sizeof(sched_job))
344 first = true;
345
346 spin_unlock(&entity->queue_lock);
347
348 /* first job wakes up scheduler */
349 if (first) {
350 /* Add the entity to the run queue */
351 amd_sched_rq_add_entity(entity->rq, entity);
352 amd_sched_wakeup(sched);
353 }
354 return added;
355 }
356
357 /* job_finish is called after hw fence signaled, and
358 * the job had already been deleted from ring_mirror_list
359 */
360 static void amd_sched_job_finish(struct work_struct *work)
361 {
362 struct amd_sched_job *s_job = container_of(work, struct amd_sched_job,
363 finish_work);
364 struct amd_gpu_scheduler *sched = s_job->sched;
365
366 /* remove job from ring_mirror_list */
367 spin_lock(&sched->job_list_lock);
368 list_del_init(&s_job->node);
369 if (sched->timeout != MAX_SCHEDULE_TIMEOUT) {
370 struct amd_sched_job *next;
371
372 spin_unlock(&sched->job_list_lock);
373 cancel_delayed_work_sync(&s_job->work_tdr);
374 spin_lock(&sched->job_list_lock);
375
376 /* queue TDR for next job */
377 next = list_first_entry_or_null(&sched->ring_mirror_list,
378 struct amd_sched_job, node);
379
380 if (next)
381 schedule_delayed_work(&next->work_tdr, sched->timeout);
382 }
383 spin_unlock(&sched->job_list_lock);
384 sched->ops->free_job(s_job);
385 }
386
387 static void amd_sched_job_finish_cb(struct dma_fence *f,
388 struct dma_fence_cb *cb)
389 {
390 struct amd_sched_job *job = container_of(cb, struct amd_sched_job,
391 finish_cb);
392 schedule_work(&job->finish_work);
393 }
394
395 static void amd_sched_job_begin(struct amd_sched_job *s_job)
396 {
397 struct amd_gpu_scheduler *sched = s_job->sched;
398
399 spin_lock(&sched->job_list_lock);
400 list_add_tail(&s_job->node, &sched->ring_mirror_list);
401 if (sched->timeout != MAX_SCHEDULE_TIMEOUT &&
402 list_first_entry_or_null(&sched->ring_mirror_list,
403 struct amd_sched_job, node) == s_job)
404 schedule_delayed_work(&s_job->work_tdr, sched->timeout);
405 spin_unlock(&sched->job_list_lock);
406 }
407
408 static void amd_sched_job_timedout(struct work_struct *work)
409 {
410 struct amd_sched_job *job = container_of(work, struct amd_sched_job,
411 work_tdr.work);
412
413 job->sched->ops->timedout_job(job);
414 }
415
416 void amd_sched_hw_job_reset(struct amd_gpu_scheduler *sched)
417 {
418 struct amd_sched_job *s_job;
419
420 spin_lock(&sched->job_list_lock);
421 list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) {
422 if (s_job->s_fence->parent &&
423 dma_fence_remove_callback(s_job->s_fence->parent,
424 &s_job->s_fence->cb)) {
425 dma_fence_put(s_job->s_fence->parent);
426 s_job->s_fence->parent = NULL;
427 atomic_dec(&sched->hw_rq_count);
428 }
429 }
430 spin_unlock(&sched->job_list_lock);
431 }
432
433 void amd_sched_job_kickout(struct amd_sched_job *s_job)
434 {
435 struct amd_gpu_scheduler *sched = s_job->sched;
436
437 spin_lock(&sched->job_list_lock);
438 list_del_init(&s_job->node);
439 spin_unlock(&sched->job_list_lock);
440 }
441
442 void amd_sched_job_recovery(struct amd_gpu_scheduler *sched)
443 {
444 struct amd_sched_job *s_job, *tmp;
445 int r;
446
447 spin_lock(&sched->job_list_lock);
448 s_job = list_first_entry_or_null(&sched->ring_mirror_list,
449 struct amd_sched_job, node);
450 if (s_job && sched->timeout != MAX_SCHEDULE_TIMEOUT)
451 schedule_delayed_work(&s_job->work_tdr, sched->timeout);
452
453 list_for_each_entry_safe(s_job, tmp, &sched->ring_mirror_list, node) {
454 struct amd_sched_fence *s_fence = s_job->s_fence;
455 struct dma_fence *fence;
456
457 spin_unlock(&sched->job_list_lock);
458 fence = sched->ops->run_job(s_job);
459 atomic_inc(&sched->hw_rq_count);
460 if (fence) {
461 s_fence->parent = dma_fence_get(fence);
462 r = dma_fence_add_callback(fence, &s_fence->cb,
463 amd_sched_process_job);
464 if (r == -ENOENT)
465 amd_sched_process_job(fence, &s_fence->cb);
466 else if (r)
467 DRM_ERROR("fence add callback failed (%d)\n",
468 r);
469 dma_fence_put(fence);
470 } else {
471 DRM_ERROR("Failed to run job!\n");
472 amd_sched_process_job(NULL, &s_fence->cb);
473 }
474 spin_lock(&sched->job_list_lock);
475 }
476 spin_unlock(&sched->job_list_lock);
477 }
478
479 /**
480 * Submit a job to the job queue
481 *
482 * @sched_job The pointer to job required to submit
483 *
484 * Returns 0 for success, negative error code otherwise.
485 */
486 void amd_sched_entity_push_job(struct amd_sched_job *sched_job)
487 {
488 struct amd_sched_entity *entity = sched_job->s_entity;
489
490 trace_amd_sched_job(sched_job);
491 dma_fence_add_callback(&sched_job->s_fence->finished, &sched_job->finish_cb,
492 amd_sched_job_finish_cb);
493 wait_event(entity->sched->job_scheduled,
494 amd_sched_entity_in(sched_job));
495 }
496
497 /* init a sched_job with basic field */
498 int amd_sched_job_init(struct amd_sched_job *job,
499 struct amd_gpu_scheduler *sched,
500 struct amd_sched_entity *entity,
501 void *owner)
502 {
503 job->sched = sched;
504 job->s_entity = entity;
505 job->s_fence = amd_sched_fence_create(entity, owner);
506 if (!job->s_fence)
507 return -ENOMEM;
508 job->id = atomic64_inc_return(&sched->job_id_count);
509
510 INIT_WORK(&job->finish_work, amd_sched_job_finish);
511 INIT_LIST_HEAD(&job->node);
512 INIT_DELAYED_WORK(&job->work_tdr, amd_sched_job_timedout);
513
514 return 0;
515 }
516
517 /**
518 * Return ture if we can push more jobs to the hw.
519 */
520 static bool amd_sched_ready(struct amd_gpu_scheduler *sched)
521 {
522 return atomic_read(&sched->hw_rq_count) <
523 sched->hw_submission_limit;
524 }
525
526 /**
527 * Wake up the scheduler when it is ready
528 */
529 static void amd_sched_wakeup(struct amd_gpu_scheduler *sched)
530 {
531 if (amd_sched_ready(sched))
532 wake_up_interruptible(&sched->wake_up_worker);
533 }
534
535 /**
536 * Select next entity to process
537 */
538 static struct amd_sched_entity *
539 amd_sched_select_entity(struct amd_gpu_scheduler *sched)
540 {
541 struct amd_sched_entity *entity;
542 int i;
543
544 if (!amd_sched_ready(sched))
545 return NULL;
546
547 /* Kernel run queue has higher priority than normal run queue*/
548 for (i = AMD_SCHED_PRIORITY_MAX - 1; i >= AMD_SCHED_PRIORITY_MIN; i--) {
549 entity = amd_sched_rq_select_entity(&sched->sched_rq[i]);
550 if (entity)
551 break;
552 }
553
554 return entity;
555 }
556
557 static void amd_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb)
558 {
559 struct amd_sched_fence *s_fence =
560 container_of(cb, struct amd_sched_fence, cb);
561 struct amd_gpu_scheduler *sched = s_fence->sched;
562
563 atomic_dec(&sched->hw_rq_count);
564 amd_sched_fence_finished(s_fence);
565
566 trace_amd_sched_process_job(s_fence);
567 dma_fence_put(&s_fence->finished);
568 wake_up_interruptible(&sched->wake_up_worker);
569 }
570
571 static bool amd_sched_blocked(struct amd_gpu_scheduler *sched)
572 {
573 if (kthread_should_park()) {
574 kthread_parkme();
575 return true;
576 }
577
578 return false;
579 }
580
581 static int amd_sched_main(void *param)
582 {
583 struct sched_param sparam = {.sched_priority = 1};
584 struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param;
585 int r, count;
586
587 sched_setscheduler(current, SCHED_FIFO, &sparam);
588
589 while (!kthread_should_stop()) {
590 struct amd_sched_entity *entity = NULL;
591 struct amd_sched_fence *s_fence;
592 struct amd_sched_job *sched_job;
593 struct dma_fence *fence;
594
595 wait_event_interruptible(sched->wake_up_worker,
596 (!amd_sched_blocked(sched) &&
597 (entity = amd_sched_select_entity(sched))) ||
598 kthread_should_stop());
599
600 if (!entity)
601 continue;
602
603 sched_job = amd_sched_entity_pop_job(entity);
604 if (!sched_job)
605 continue;
606
607 s_fence = sched_job->s_fence;
608
609 atomic_inc(&sched->hw_rq_count);
610 amd_sched_job_begin(sched_job);
611
612 fence = sched->ops->run_job(sched_job);
613 amd_sched_fence_scheduled(s_fence);
614 if (fence) {
615 s_fence->parent = dma_fence_get(fence);
616 r = dma_fence_add_callback(fence, &s_fence->cb,
617 amd_sched_process_job);
618 if (r == -ENOENT)
619 amd_sched_process_job(fence, &s_fence->cb);
620 else if (r)
621 DRM_ERROR("fence add callback failed (%d)\n",
622 r);
623 dma_fence_put(fence);
624 } else {
625 DRM_ERROR("Failed to run job!\n");
626 amd_sched_process_job(NULL, &s_fence->cb);
627 }
628
629 count = kfifo_out(&entity->job_queue, &sched_job,
630 sizeof(sched_job));
631 WARN_ON(count != sizeof(sched_job));
632 wake_up(&sched->job_scheduled);
633 }
634 return 0;
635 }
636
637 /**
638 * Init a gpu scheduler instance
639 *
640 * @sched The pointer to the scheduler
641 * @ops The backend operations for this scheduler.
642 * @hw_submissions Number of hw submissions to do.
643 * @name Name used for debugging
644 *
645 * Return 0 on success, otherwise error code.
646 */
647 int amd_sched_init(struct amd_gpu_scheduler *sched,
648 const struct amd_sched_backend_ops *ops,
649 unsigned hw_submission, long timeout, const char *name)
650 {
651 int i;
652 sched->ops = ops;
653 sched->hw_submission_limit = hw_submission;
654 sched->name = name;
655 sched->timeout = timeout;
656 for (i = AMD_SCHED_PRIORITY_MIN; i < AMD_SCHED_PRIORITY_MAX; i++)
657 amd_sched_rq_init(&sched->sched_rq[i]);
658
659 init_waitqueue_head(&sched->wake_up_worker);
660 init_waitqueue_head(&sched->job_scheduled);
661 INIT_LIST_HEAD(&sched->ring_mirror_list);
662 spin_lock_init(&sched->job_list_lock);
663 atomic_set(&sched->hw_rq_count, 0);
664 atomic64_set(&sched->job_id_count, 0);
665
666 /* Each scheduler will run on a seperate kernel thread */
667 sched->thread = kthread_run(amd_sched_main, sched, sched->name);
668 if (IS_ERR(sched->thread)) {
669 DRM_ERROR("Failed to create scheduler for %s.\n", name);
670 return PTR_ERR(sched->thread);
671 }
672
673 return 0;
674 }
675
676 /**
677 * Destroy a gpu scheduler
678 *
679 * @sched The pointer to the scheduler
680 */
681 void amd_sched_fini(struct amd_gpu_scheduler *sched)
682 {
683 if (sched->thread)
684 kthread_stop(sched->thread);
685 }