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 /**
25 * DOC: Overview
26 *
27 * The GPU scheduler provides entities which allow userspace to push jobs
28 * into software queues which are then scheduled on a hardware run queue.
29 * The software queues have a priority among them. The scheduler selects the entities
30 * from the run queue using a FIFO. The scheduler provides dependency handling
31 * features among jobs. The driver is supposed to provide callback functions for
32 * backend operations to the scheduler like submitting a job to hardware run queue,
33 * returning the dependencies of a job etc.
34 *
35 * The organisation of the scheduler is the following:
36 *
37 * 1. Each hw run queue has one scheduler
38 * 2. Each scheduler has multiple run queues with different priorities
39 * (e.g., HIGH_HW,HIGH_SW, KERNEL, NORMAL)
40 * 3. Each scheduler run queue has a queue of entities to schedule
41 * 4. Entities themselves maintain a queue of jobs that will be scheduled on
42 * the hardware.
43 *
44 * The jobs in a entity are always scheduled in the order that they were pushed.
45 *
46 * Note that once a job was taken from the entities queue and pushed to the
47 * hardware, i.e. the pending queue, the entity must not be referenced anymore
48 * through the jobs entity pointer.
49 */
50
51 /**
52 * DOC: Flow Control
53 *
54 * The DRM GPU scheduler provides a flow control mechanism to regulate the rate
55 * in which the jobs fetched from scheduler entities are executed.
56 *
57 * In this context the &drm_gpu_scheduler keeps track of a driver specified
58 * credit limit representing the capacity of this scheduler and a credit count;
59 * every &drm_sched_job carries a driver specified number of credits.
60 *
61 * Once a job is executed (but not yet finished), the job's credits contribute
62 * to the scheduler's credit count until the job is finished. If by executing
63 * one more job the scheduler's credit count would exceed the scheduler's
64 * credit limit, the job won't be executed. Instead, the scheduler will wait
65 * until the credit count has decreased enough to not overflow its credit limit.
66 * This implies waiting for previously executed jobs.
67 *
68 * Optionally, drivers may register a callback (update_job_credits) provided by
69 * struct drm_sched_backend_ops to update the job's credits dynamically. The
70 * scheduler executes this callback every time the scheduler considers a job for
71 * execution and subsequently checks whether the job fits the scheduler's credit
72 * limit.
73 */
74
75 #include <linux/wait.h>
76 #include <linux/sched.h>
77 #include <linux/completion.h>
78 #include <linux/dma-resv.h>
79 #ifdef __linux__
80 #include <uapi/linux/sched/types.h>
81 #endif
82
83 #include <drm/drm_print.h>
84 #include <drm/drm_gem.h>
85 #include <drm/drm_syncobj.h>
86 #include <drm/gpu_scheduler.h>
87 #include <drm/spsc_queue.h>
88
89 #define CREATE_TRACE_POINTS
90 #include "gpu_scheduler_trace.h"
91
92 #ifdef CONFIG_LOCKDEP
93 static struct lockdep_map drm_sched_lockdep_map = {
94 .name = "drm_sched_lockdep_map"
95 };
96 #endif
97
98 #define to_drm_sched_job(sched_job) \
99 container_of((sched_job), struct drm_sched_job, queue_node)
100
101 int drm_sched_policy = DRM_SCHED_POLICY_FIFO;
102
103 /**
104 * DOC: sched_policy (int)
105 * Used to override default entities scheduling policy in a run queue.
106 */
107 MODULE_PARM_DESC(sched_policy, "Specify the scheduling policy for entities on a run-queue, " __stringify(DRM_SCHED_POLICY_RR) " = Round Robin, " __stringify(DRM_SCHED_POLICY_FIFO) " = FIFO (default).");
108 module_param_named(sched_policy, drm_sched_policy, int, 0444);
109
drm_sched_available_credits(struct drm_gpu_scheduler * sched)110 static u32 drm_sched_available_credits(struct drm_gpu_scheduler *sched)
111 {
112 u32 credits;
113
114 drm_WARN_ON(sched, check_sub_overflow(sched->credit_limit,
115 atomic_read(&sched->credit_count),
116 &credits));
117
118 return credits;
119 }
120
121 /**
122 * drm_sched_can_queue -- Can we queue more to the hardware?
123 * @sched: scheduler instance
124 * @entity: the scheduler entity
125 *
126 * Return true if we can push at least one more job from @entity, false
127 * otherwise.
128 */
drm_sched_can_queue(struct drm_gpu_scheduler * sched,struct drm_sched_entity * entity)129 static bool drm_sched_can_queue(struct drm_gpu_scheduler *sched,
130 struct drm_sched_entity *entity)
131 {
132 struct drm_sched_job *s_job;
133
134 s_job = to_drm_sched_job(spsc_queue_peek(&entity->job_queue));
135 if (!s_job)
136 return false;
137
138 if (sched->ops->update_job_credits) {
139 s_job->credits = sched->ops->update_job_credits(s_job);
140
141 drm_WARN(sched, !s_job->credits,
142 "Jobs with zero credits bypass job-flow control.\n");
143 }
144
145 /* If a job exceeds the credit limit, truncate it to the credit limit
146 * itself to guarantee forward progress.
147 */
148 if (drm_WARN(sched, s_job->credits > sched->credit_limit,
149 "Jobs may not exceed the credit limit, truncate.\n"))
150 s_job->credits = sched->credit_limit;
151
152 return drm_sched_available_credits(sched) >= s_job->credits;
153 }
154
drm_sched_entity_compare_before(struct rb_node * a,const struct rb_node * b)155 static __always_inline bool drm_sched_entity_compare_before(struct rb_node *a,
156 const struct rb_node *b)
157 {
158 struct drm_sched_entity *ent_a = rb_entry((a), struct drm_sched_entity, rb_tree_node);
159 struct drm_sched_entity *ent_b = rb_entry((b), struct drm_sched_entity, rb_tree_node);
160
161 return ktime_before(ent_a->oldest_job_waiting, ent_b->oldest_job_waiting);
162 }
163
drm_sched_rq_remove_fifo_locked(struct drm_sched_entity * entity)164 static inline void drm_sched_rq_remove_fifo_locked(struct drm_sched_entity *entity)
165 {
166 struct drm_sched_rq *rq = entity->rq;
167
168 if (!RB_EMPTY_NODE(&entity->rb_tree_node)) {
169 rb_erase_cached(&entity->rb_tree_node, &rq->rb_tree_root);
170 RB_CLEAR_NODE(&entity->rb_tree_node);
171 }
172 }
173
drm_sched_rq_update_fifo(struct drm_sched_entity * entity,ktime_t ts)174 void drm_sched_rq_update_fifo(struct drm_sched_entity *entity, ktime_t ts)
175 {
176 /*
177 * Both locks need to be grabbed, one to protect from entity->rq change
178 * for entity from within concurrent drm_sched_entity_select_rq and the
179 * other to update the rb tree structure.
180 */
181 spin_lock(&entity->rq_lock);
182 spin_lock(&entity->rq->lock);
183
184 drm_sched_rq_remove_fifo_locked(entity);
185
186 entity->oldest_job_waiting = ts;
187
188 rb_add_cached(&entity->rb_tree_node, &entity->rq->rb_tree_root,
189 drm_sched_entity_compare_before);
190
191 spin_unlock(&entity->rq->lock);
192 spin_unlock(&entity->rq_lock);
193 }
194
195 /**
196 * drm_sched_rq_init - initialize a given run queue struct
197 *
198 * @sched: scheduler instance to associate with this run queue
199 * @rq: scheduler run queue
200 *
201 * Initializes a scheduler runqueue.
202 */
drm_sched_rq_init(struct drm_gpu_scheduler * sched,struct drm_sched_rq * rq)203 static void drm_sched_rq_init(struct drm_gpu_scheduler *sched,
204 struct drm_sched_rq *rq)
205 {
206 mtx_init(&rq->lock, IPL_NONE);
207 INIT_LIST_HEAD(&rq->entities);
208 rq->rb_tree_root = RB_ROOT_CACHED;
209 rq->current_entity = NULL;
210 rq->sched = sched;
211 }
212
213 /**
214 * drm_sched_rq_add_entity - add an entity
215 *
216 * @rq: scheduler run queue
217 * @entity: scheduler entity
218 *
219 * Adds a scheduler entity to the run queue.
220 */
drm_sched_rq_add_entity(struct drm_sched_rq * rq,struct drm_sched_entity * entity)221 void drm_sched_rq_add_entity(struct drm_sched_rq *rq,
222 struct drm_sched_entity *entity)
223 {
224 if (!list_empty(&entity->list))
225 return;
226
227 spin_lock(&rq->lock);
228
229 atomic_inc(rq->sched->score);
230 list_add_tail(&entity->list, &rq->entities);
231
232 spin_unlock(&rq->lock);
233 }
234
235 /**
236 * drm_sched_rq_remove_entity - remove an entity
237 *
238 * @rq: scheduler run queue
239 * @entity: scheduler entity
240 *
241 * Removes a scheduler entity from the run queue.
242 */
drm_sched_rq_remove_entity(struct drm_sched_rq * rq,struct drm_sched_entity * entity)243 void drm_sched_rq_remove_entity(struct drm_sched_rq *rq,
244 struct drm_sched_entity *entity)
245 {
246 if (list_empty(&entity->list))
247 return;
248
249 spin_lock(&rq->lock);
250
251 atomic_dec(rq->sched->score);
252 list_del_init(&entity->list);
253
254 if (rq->current_entity == entity)
255 rq->current_entity = NULL;
256
257 if (drm_sched_policy == DRM_SCHED_POLICY_FIFO)
258 drm_sched_rq_remove_fifo_locked(entity);
259
260 spin_unlock(&rq->lock);
261 }
262
263 /**
264 * drm_sched_rq_select_entity_rr - Select an entity which could provide a job to run
265 *
266 * @sched: the gpu scheduler
267 * @rq: scheduler run queue to check.
268 *
269 * Try to find the next ready entity.
270 *
271 * Return an entity if one is found; return an error-pointer (!NULL) if an
272 * entity was ready, but the scheduler had insufficient credits to accommodate
273 * its job; return NULL, if no ready entity was found.
274 */
275 static struct drm_sched_entity *
drm_sched_rq_select_entity_rr(struct drm_gpu_scheduler * sched,struct drm_sched_rq * rq)276 drm_sched_rq_select_entity_rr(struct drm_gpu_scheduler *sched,
277 struct drm_sched_rq *rq)
278 {
279 struct drm_sched_entity *entity;
280
281 spin_lock(&rq->lock);
282
283 entity = rq->current_entity;
284 if (entity) {
285 list_for_each_entry_continue(entity, &rq->entities, list) {
286 if (drm_sched_entity_is_ready(entity)) {
287 /* If we can't queue yet, preserve the current
288 * entity in terms of fairness.
289 */
290 if (!drm_sched_can_queue(sched, entity)) {
291 spin_unlock(&rq->lock);
292 return ERR_PTR(-ENOSPC);
293 }
294
295 rq->current_entity = entity;
296 reinit_completion(&entity->entity_idle);
297 spin_unlock(&rq->lock);
298 return entity;
299 }
300 }
301 }
302
303 list_for_each_entry(entity, &rq->entities, list) {
304 if (drm_sched_entity_is_ready(entity)) {
305 /* If we can't queue yet, preserve the current entity in
306 * terms of fairness.
307 */
308 if (!drm_sched_can_queue(sched, entity)) {
309 spin_unlock(&rq->lock);
310 return ERR_PTR(-ENOSPC);
311 }
312
313 rq->current_entity = entity;
314 reinit_completion(&entity->entity_idle);
315 spin_unlock(&rq->lock);
316 return entity;
317 }
318
319 if (entity == rq->current_entity)
320 break;
321 }
322
323 spin_unlock(&rq->lock);
324
325 return NULL;
326 }
327
328 /**
329 * drm_sched_rq_select_entity_fifo - Select an entity which provides a job to run
330 *
331 * @sched: the gpu scheduler
332 * @rq: scheduler run queue to check.
333 *
334 * Find oldest waiting ready entity.
335 *
336 * Return an entity if one is found; return an error-pointer (!NULL) if an
337 * entity was ready, but the scheduler had insufficient credits to accommodate
338 * its job; return NULL, if no ready entity was found.
339 */
340 static struct drm_sched_entity *
drm_sched_rq_select_entity_fifo(struct drm_gpu_scheduler * sched,struct drm_sched_rq * rq)341 drm_sched_rq_select_entity_fifo(struct drm_gpu_scheduler *sched,
342 struct drm_sched_rq *rq)
343 {
344 struct rb_node *rb;
345
346 spin_lock(&rq->lock);
347 for (rb = rb_first_cached(&rq->rb_tree_root); rb; rb = rb_next(rb)) {
348 struct drm_sched_entity *entity;
349
350 entity = rb_entry(rb, struct drm_sched_entity, rb_tree_node);
351 if (drm_sched_entity_is_ready(entity)) {
352 /* If we can't queue yet, preserve the current entity in
353 * terms of fairness.
354 */
355 if (!drm_sched_can_queue(sched, entity)) {
356 spin_unlock(&rq->lock);
357 return ERR_PTR(-ENOSPC);
358 }
359
360 rq->current_entity = entity;
361 reinit_completion(&entity->entity_idle);
362 break;
363 }
364 }
365 spin_unlock(&rq->lock);
366
367 return rb ? rb_entry(rb, struct drm_sched_entity, rb_tree_node) : NULL;
368 }
369
370 /**
371 * drm_sched_run_job_queue - enqueue run-job work
372 * @sched: scheduler instance
373 */
drm_sched_run_job_queue(struct drm_gpu_scheduler * sched)374 static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched)
375 {
376 if (!READ_ONCE(sched->pause_submit))
377 queue_work(sched->submit_wq, &sched->work_run_job);
378 }
379
380 /**
381 * __drm_sched_run_free_queue - enqueue free-job work
382 * @sched: scheduler instance
383 */
__drm_sched_run_free_queue(struct drm_gpu_scheduler * sched)384 static void __drm_sched_run_free_queue(struct drm_gpu_scheduler *sched)
385 {
386 if (!READ_ONCE(sched->pause_submit))
387 queue_work(sched->submit_wq, &sched->work_free_job);
388 }
389
390 /**
391 * drm_sched_run_free_queue - enqueue free-job work if ready
392 * @sched: scheduler instance
393 */
drm_sched_run_free_queue(struct drm_gpu_scheduler * sched)394 static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched)
395 {
396 struct drm_sched_job *job;
397
398 spin_lock(&sched->job_list_lock);
399 job = list_first_entry_or_null(&sched->pending_list,
400 struct drm_sched_job, list);
401 if (job && dma_fence_is_signaled(&job->s_fence->finished))
402 __drm_sched_run_free_queue(sched);
403 spin_unlock(&sched->job_list_lock);
404 }
405
406 /**
407 * drm_sched_job_done - complete a job
408 * @s_job: pointer to the job which is done
409 *
410 * Finish the job's fence and wake up the worker thread.
411 */
drm_sched_job_done(struct drm_sched_job * s_job,int result)412 static void drm_sched_job_done(struct drm_sched_job *s_job, int result)
413 {
414 struct drm_sched_fence *s_fence = s_job->s_fence;
415 struct drm_gpu_scheduler *sched = s_fence->sched;
416
417 atomic_sub(s_job->credits, &sched->credit_count);
418 atomic_dec(sched->score);
419
420 trace_drm_sched_process_job(s_fence);
421
422 dma_fence_get(&s_fence->finished);
423 drm_sched_fence_finished(s_fence, result);
424 dma_fence_put(&s_fence->finished);
425 __drm_sched_run_free_queue(sched);
426 }
427
428 /**
429 * drm_sched_job_done_cb - the callback for a done job
430 * @f: fence
431 * @cb: fence callbacks
432 */
drm_sched_job_done_cb(struct dma_fence * f,struct dma_fence_cb * cb)433 static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb)
434 {
435 struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb);
436
437 drm_sched_job_done(s_job, f->error);
438 }
439
440 /**
441 * drm_sched_start_timeout - start timeout for reset worker
442 *
443 * @sched: scheduler instance to start the worker for
444 *
445 * Start the timeout for the given scheduler.
446 */
drm_sched_start_timeout(struct drm_gpu_scheduler * sched)447 static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched)
448 {
449 lockdep_assert_held(&sched->job_list_lock);
450
451 if (sched->timeout != MAX_SCHEDULE_TIMEOUT &&
452 !list_empty(&sched->pending_list))
453 mod_delayed_work(sched->timeout_wq, &sched->work_tdr, sched->timeout);
454 }
455
drm_sched_start_timeout_unlocked(struct drm_gpu_scheduler * sched)456 static void drm_sched_start_timeout_unlocked(struct drm_gpu_scheduler *sched)
457 {
458 spin_lock(&sched->job_list_lock);
459 drm_sched_start_timeout(sched);
460 spin_unlock(&sched->job_list_lock);
461 }
462
463 /**
464 * drm_sched_tdr_queue_imm: - immediately start job timeout handler
465 *
466 * @sched: scheduler for which the timeout handling should be started.
467 *
468 * Start timeout handling immediately for the named scheduler.
469 */
drm_sched_tdr_queue_imm(struct drm_gpu_scheduler * sched)470 void drm_sched_tdr_queue_imm(struct drm_gpu_scheduler *sched)
471 {
472 spin_lock(&sched->job_list_lock);
473 sched->timeout = 0;
474 drm_sched_start_timeout(sched);
475 spin_unlock(&sched->job_list_lock);
476 }
477 EXPORT_SYMBOL(drm_sched_tdr_queue_imm);
478
479 /**
480 * drm_sched_fault - immediately start timeout handler
481 *
482 * @sched: scheduler where the timeout handling should be started.
483 *
484 * Start timeout handling immediately when the driver detects a hardware fault.
485 */
drm_sched_fault(struct drm_gpu_scheduler * sched)486 void drm_sched_fault(struct drm_gpu_scheduler *sched)
487 {
488 if (sched->timeout_wq)
489 mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0);
490 }
491 EXPORT_SYMBOL(drm_sched_fault);
492
493 /**
494 * drm_sched_suspend_timeout - Suspend scheduler job timeout
495 *
496 * @sched: scheduler instance for which to suspend the timeout
497 *
498 * Suspend the delayed work timeout for the scheduler. This is done by
499 * modifying the delayed work timeout to an arbitrary large value,
500 * MAX_SCHEDULE_TIMEOUT in this case.
501 *
502 * Returns the timeout remaining
503 *
504 */
drm_sched_suspend_timeout(struct drm_gpu_scheduler * sched)505 unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched)
506 {
507 unsigned long sched_timeout, now = jiffies;
508
509 #ifdef __linux__
510 sched_timeout = sched->work_tdr.timer.expires;
511 #else
512 sched_timeout = sched->work_tdr.to.to_time;
513 #endif
514
515 /*
516 * Modify the timeout to an arbitrarily large value. This also prevents
517 * the timeout to be restarted when new submissions arrive
518 */
519 if (mod_delayed_work(sched->timeout_wq, &sched->work_tdr, MAX_SCHEDULE_TIMEOUT)
520 && time_after(sched_timeout, now))
521 return sched_timeout - now;
522 else
523 return sched->timeout;
524 }
525 EXPORT_SYMBOL(drm_sched_suspend_timeout);
526
527 /**
528 * drm_sched_resume_timeout - Resume scheduler job timeout
529 *
530 * @sched: scheduler instance for which to resume the timeout
531 * @remaining: remaining timeout
532 *
533 * Resume the delayed work timeout for the scheduler.
534 */
drm_sched_resume_timeout(struct drm_gpu_scheduler * sched,unsigned long remaining)535 void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched,
536 unsigned long remaining)
537 {
538 spin_lock(&sched->job_list_lock);
539
540 if (list_empty(&sched->pending_list))
541 cancel_delayed_work(&sched->work_tdr);
542 else
543 mod_delayed_work(sched->timeout_wq, &sched->work_tdr, remaining);
544
545 spin_unlock(&sched->job_list_lock);
546 }
547 EXPORT_SYMBOL(drm_sched_resume_timeout);
548
drm_sched_job_begin(struct drm_sched_job * s_job)549 static void drm_sched_job_begin(struct drm_sched_job *s_job)
550 {
551 struct drm_gpu_scheduler *sched = s_job->sched;
552
553 spin_lock(&sched->job_list_lock);
554 list_add_tail(&s_job->list, &sched->pending_list);
555 drm_sched_start_timeout(sched);
556 spin_unlock(&sched->job_list_lock);
557 }
558
drm_sched_job_timedout(struct work_struct * work)559 static void drm_sched_job_timedout(struct work_struct *work)
560 {
561 struct drm_gpu_scheduler *sched;
562 struct drm_sched_job *job;
563 enum drm_gpu_sched_stat status = DRM_GPU_SCHED_STAT_NOMINAL;
564
565 sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work);
566
567 /* Protects against concurrent deletion in drm_sched_get_finished_job */
568 spin_lock(&sched->job_list_lock);
569 job = list_first_entry_or_null(&sched->pending_list,
570 struct drm_sched_job, list);
571
572 if (job) {
573 /*
574 * Remove the bad job so it cannot be freed by concurrent
575 * drm_sched_cleanup_jobs. It will be reinserted back after sched->thread
576 * is parked at which point it's safe.
577 */
578 list_del_init(&job->list);
579 spin_unlock(&sched->job_list_lock);
580
581 status = job->sched->ops->timedout_job(job);
582
583 /*
584 * Guilty job did complete and hence needs to be manually removed
585 * See drm_sched_stop doc.
586 */
587 if (sched->free_guilty) {
588 job->sched->ops->free_job(job);
589 sched->free_guilty = false;
590 }
591 } else {
592 spin_unlock(&sched->job_list_lock);
593 }
594
595 if (status != DRM_GPU_SCHED_STAT_ENODEV)
596 drm_sched_start_timeout_unlocked(sched);
597 }
598
599 /**
600 * drm_sched_stop - stop the scheduler
601 *
602 * @sched: scheduler instance
603 * @bad: job which caused the time out
604 *
605 * Stop the scheduler and also removes and frees all completed jobs.
606 * Note: bad job will not be freed as it might be used later and so it's
607 * callers responsibility to release it manually if it's not part of the
608 * pending list any more.
609 *
610 */
drm_sched_stop(struct drm_gpu_scheduler * sched,struct drm_sched_job * bad)611 void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad)
612 {
613 struct drm_sched_job *s_job, *tmp;
614
615 drm_sched_wqueue_stop(sched);
616
617 /*
618 * Reinsert back the bad job here - now it's safe as
619 * drm_sched_get_finished_job cannot race against us and release the
620 * bad job at this point - we parked (waited for) any in progress
621 * (earlier) cleanups and drm_sched_get_finished_job will not be called
622 * now until the scheduler thread is unparked.
623 */
624 if (bad && bad->sched == sched)
625 /*
626 * Add at the head of the queue to reflect it was the earliest
627 * job extracted.
628 */
629 list_add(&bad->list, &sched->pending_list);
630
631 /*
632 * Iterate the job list from later to earlier one and either deactive
633 * their HW callbacks or remove them from pending list if they already
634 * signaled.
635 * This iteration is thread safe as sched thread is stopped.
636 */
637 list_for_each_entry_safe_reverse(s_job, tmp, &sched->pending_list,
638 list) {
639 if (s_job->s_fence->parent &&
640 dma_fence_remove_callback(s_job->s_fence->parent,
641 &s_job->cb)) {
642 dma_fence_put(s_job->s_fence->parent);
643 s_job->s_fence->parent = NULL;
644 atomic_sub(s_job->credits, &sched->credit_count);
645 } else {
646 /*
647 * remove job from pending_list.
648 * Locking here is for concurrent resume timeout
649 */
650 spin_lock(&sched->job_list_lock);
651 list_del_init(&s_job->list);
652 spin_unlock(&sched->job_list_lock);
653
654 /*
655 * Wait for job's HW fence callback to finish using s_job
656 * before releasing it.
657 *
658 * Job is still alive so fence refcount at least 1
659 */
660 dma_fence_wait(&s_job->s_fence->finished, false);
661
662 /*
663 * We must keep bad job alive for later use during
664 * recovery by some of the drivers but leave a hint
665 * that the guilty job must be released.
666 */
667 if (bad != s_job)
668 sched->ops->free_job(s_job);
669 else
670 sched->free_guilty = true;
671 }
672 }
673
674 /*
675 * Stop pending timer in flight as we rearm it in drm_sched_start. This
676 * avoids the pending timeout work in progress to fire right away after
677 * this TDR finished and before the newly restarted jobs had a
678 * chance to complete.
679 */
680 cancel_delayed_work(&sched->work_tdr);
681 }
682
683 EXPORT_SYMBOL(drm_sched_stop);
684
685 /**
686 * drm_sched_start - recover jobs after a reset
687 *
688 * @sched: scheduler instance
689 *
690 */
drm_sched_start(struct drm_gpu_scheduler * sched)691 void drm_sched_start(struct drm_gpu_scheduler *sched)
692 {
693 struct drm_sched_job *s_job, *tmp;
694
695 /*
696 * Locking the list is not required here as the sched thread is parked
697 * so no new jobs are being inserted or removed. Also concurrent
698 * GPU recovers can't run in parallel.
699 */
700 list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
701 struct dma_fence *fence = s_job->s_fence->parent;
702
703 atomic_add(s_job->credits, &sched->credit_count);
704
705 if (!fence) {
706 drm_sched_job_done(s_job, -ECANCELED);
707 continue;
708 }
709
710 if (dma_fence_add_callback(fence, &s_job->cb,
711 drm_sched_job_done_cb))
712 drm_sched_job_done(s_job, fence->error);
713 }
714
715 drm_sched_start_timeout_unlocked(sched);
716 drm_sched_wqueue_start(sched);
717 }
718 EXPORT_SYMBOL(drm_sched_start);
719
720 /**
721 * drm_sched_resubmit_jobs - Deprecated, don't use in new code!
722 *
723 * @sched: scheduler instance
724 *
725 * Re-submitting jobs was a concept AMD came up as cheap way to implement
726 * recovery after a job timeout.
727 *
728 * This turned out to be not working very well. First of all there are many
729 * problem with the dma_fence implementation and requirements. Either the
730 * implementation is risking deadlocks with core memory management or violating
731 * documented implementation details of the dma_fence object.
732 *
733 * Drivers can still save and restore their state for recovery operations, but
734 * we shouldn't make this a general scheduler feature around the dma_fence
735 * interface.
736 */
drm_sched_resubmit_jobs(struct drm_gpu_scheduler * sched)737 void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
738 {
739 struct drm_sched_job *s_job, *tmp;
740 uint64_t guilty_context;
741 bool found_guilty = false;
742 struct dma_fence *fence;
743
744 list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
745 struct drm_sched_fence *s_fence = s_job->s_fence;
746
747 if (!found_guilty && atomic_read(&s_job->karma) > sched->hang_limit) {
748 found_guilty = true;
749 guilty_context = s_job->s_fence->scheduled.context;
750 }
751
752 if (found_guilty && s_job->s_fence->scheduled.context == guilty_context)
753 dma_fence_set_error(&s_fence->finished, -ECANCELED);
754
755 fence = sched->ops->run_job(s_job);
756
757 if (IS_ERR_OR_NULL(fence)) {
758 if (IS_ERR(fence))
759 dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
760
761 s_job->s_fence->parent = NULL;
762 } else {
763
764 s_job->s_fence->parent = dma_fence_get(fence);
765
766 /* Drop for orignal kref_init */
767 dma_fence_put(fence);
768 }
769 }
770 }
771 EXPORT_SYMBOL(drm_sched_resubmit_jobs);
772
773 /**
774 * drm_sched_job_init - init a scheduler job
775 * @job: scheduler job to init
776 * @entity: scheduler entity to use
777 * @credits: the number of credits this job contributes to the schedulers
778 * credit limit
779 * @owner: job owner for debugging
780 *
781 * Refer to drm_sched_entity_push_job() documentation
782 * for locking considerations.
783 *
784 * Drivers must make sure drm_sched_job_cleanup() if this function returns
785 * successfully, even when @job is aborted before drm_sched_job_arm() is called.
786 *
787 * WARNING: amdgpu abuses &drm_sched.ready to signal when the hardware
788 * has died, which can mean that there's no valid runqueue for a @entity.
789 * This function returns -ENOENT in this case (which probably should be -EIO as
790 * a more meanigful return value).
791 *
792 * Returns 0 for success, negative error code otherwise.
793 */
drm_sched_job_init(struct drm_sched_job * job,struct drm_sched_entity * entity,u32 credits,void * owner)794 int drm_sched_job_init(struct drm_sched_job *job,
795 struct drm_sched_entity *entity,
796 u32 credits, void *owner)
797 {
798 if (!entity->rq) {
799 /* This will most likely be followed by missing frames
800 * or worse--a blank screen--leave a trail in the
801 * logs, so this can be debugged easier.
802 */
803 drm_err(job->sched, "%s: entity has no rq!\n", __func__);
804 return -ENOENT;
805 }
806
807 if (unlikely(!credits)) {
808 pr_err("*ERROR* %s: credits cannot be 0!\n", __func__);
809 return -EINVAL;
810 }
811
812 /*
813 * We don't know for sure how the user has allocated. Thus, zero the
814 * struct so that unallowed (i.e., too early) usage of pointers that
815 * this function does not set is guaranteed to lead to a NULL pointer
816 * exception instead of UB.
817 */
818 memset(job, 0, sizeof(*job));
819
820 job->entity = entity;
821 job->credits = credits;
822 job->s_fence = drm_sched_fence_alloc(entity, owner);
823 if (!job->s_fence)
824 return -ENOMEM;
825
826 INIT_LIST_HEAD(&job->list);
827
828 xa_init_flags(&job->dependencies, XA_FLAGS_ALLOC);
829
830 return 0;
831 }
832 EXPORT_SYMBOL(drm_sched_job_init);
833
834 /**
835 * drm_sched_job_arm - arm a scheduler job for execution
836 * @job: scheduler job to arm
837 *
838 * This arms a scheduler job for execution. Specifically it initializes the
839 * &drm_sched_job.s_fence of @job, so that it can be attached to struct dma_resv
840 * or other places that need to track the completion of this job.
841 *
842 * Refer to drm_sched_entity_push_job() documentation for locking
843 * considerations.
844 *
845 * This can only be called if drm_sched_job_init() succeeded.
846 */
drm_sched_job_arm(struct drm_sched_job * job)847 void drm_sched_job_arm(struct drm_sched_job *job)
848 {
849 struct drm_gpu_scheduler *sched;
850 struct drm_sched_entity *entity = job->entity;
851
852 BUG_ON(!entity);
853 drm_sched_entity_select_rq(entity);
854 sched = entity->rq->sched;
855
856 job->sched = sched;
857 job->s_priority = entity->priority;
858 job->id = atomic64_inc_return(&sched->job_id_count);
859
860 drm_sched_fence_init(job->s_fence, job->entity);
861 }
862 EXPORT_SYMBOL(drm_sched_job_arm);
863
864 /**
865 * drm_sched_job_add_dependency - adds the fence as a job dependency
866 * @job: scheduler job to add the dependencies to
867 * @fence: the dma_fence to add to the list of dependencies.
868 *
869 * Note that @fence is consumed in both the success and error cases.
870 *
871 * Returns:
872 * 0 on success, or an error on failing to expand the array.
873 */
drm_sched_job_add_dependency(struct drm_sched_job * job,struct dma_fence * fence)874 int drm_sched_job_add_dependency(struct drm_sched_job *job,
875 struct dma_fence *fence)
876 {
877 struct dma_fence *entry;
878 unsigned long index;
879 u32 id = 0;
880 int ret;
881
882 if (!fence)
883 return 0;
884
885 /* Deduplicate if we already depend on a fence from the same context.
886 * This lets the size of the array of deps scale with the number of
887 * engines involved, rather than the number of BOs.
888 */
889 xa_for_each(&job->dependencies, index, entry) {
890 if (entry->context != fence->context)
891 continue;
892
893 if (dma_fence_is_later(fence, entry)) {
894 dma_fence_put(entry);
895 xa_store(&job->dependencies, index, fence, GFP_KERNEL);
896 } else {
897 dma_fence_put(fence);
898 }
899 return 0;
900 }
901
902 ret = xa_alloc(&job->dependencies, &id, fence, xa_limit_32b, GFP_KERNEL);
903 if (ret != 0)
904 dma_fence_put(fence);
905
906 return ret;
907 }
908 EXPORT_SYMBOL(drm_sched_job_add_dependency);
909
910 /**
911 * drm_sched_job_add_syncobj_dependency - adds a syncobj's fence as a job dependency
912 * @job: scheduler job to add the dependencies to
913 * @file: drm file private pointer
914 * @handle: syncobj handle to lookup
915 * @point: timeline point
916 *
917 * This adds the fence matching the given syncobj to @job.
918 *
919 * Returns:
920 * 0 on success, or an error on failing to expand the array.
921 */
drm_sched_job_add_syncobj_dependency(struct drm_sched_job * job,struct drm_file * file,u32 handle,u32 point)922 int drm_sched_job_add_syncobj_dependency(struct drm_sched_job *job,
923 struct drm_file *file,
924 u32 handle,
925 u32 point)
926 {
927 struct dma_fence *fence;
928 int ret;
929
930 ret = drm_syncobj_find_fence(file, handle, point, 0, &fence);
931 if (ret)
932 return ret;
933
934 return drm_sched_job_add_dependency(job, fence);
935 }
936 EXPORT_SYMBOL(drm_sched_job_add_syncobj_dependency);
937
938 /**
939 * drm_sched_job_add_resv_dependencies - add all fences from the resv to the job
940 * @job: scheduler job to add the dependencies to
941 * @resv: the dma_resv object to get the fences from
942 * @usage: the dma_resv_usage to use to filter the fences
943 *
944 * This adds all fences matching the given usage from @resv to @job.
945 * Must be called with the @resv lock held.
946 *
947 * Returns:
948 * 0 on success, or an error on failing to expand the array.
949 */
drm_sched_job_add_resv_dependencies(struct drm_sched_job * job,struct dma_resv * resv,enum dma_resv_usage usage)950 int drm_sched_job_add_resv_dependencies(struct drm_sched_job *job,
951 struct dma_resv *resv,
952 enum dma_resv_usage usage)
953 {
954 struct dma_resv_iter cursor;
955 struct dma_fence *fence;
956 int ret;
957
958 dma_resv_assert_held(resv);
959
960 dma_resv_for_each_fence(&cursor, resv, usage, fence) {
961 /* Make sure to grab an additional ref on the added fence */
962 dma_fence_get(fence);
963 ret = drm_sched_job_add_dependency(job, fence);
964 if (ret) {
965 dma_fence_put(fence);
966 return ret;
967 }
968 }
969 return 0;
970 }
971 EXPORT_SYMBOL(drm_sched_job_add_resv_dependencies);
972
973 /**
974 * drm_sched_job_add_implicit_dependencies - adds implicit dependencies as job
975 * dependencies
976 * @job: scheduler job to add the dependencies to
977 * @obj: the gem object to add new dependencies from.
978 * @write: whether the job might write the object (so we need to depend on
979 * shared fences in the reservation object).
980 *
981 * This should be called after drm_gem_lock_reservations() on your array of
982 * GEM objects used in the job but before updating the reservations with your
983 * own fences.
984 *
985 * Returns:
986 * 0 on success, or an error on failing to expand the array.
987 */
drm_sched_job_add_implicit_dependencies(struct drm_sched_job * job,struct drm_gem_object * obj,bool write)988 int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
989 struct drm_gem_object *obj,
990 bool write)
991 {
992 return drm_sched_job_add_resv_dependencies(job, obj->resv,
993 dma_resv_usage_rw(write));
994 }
995 EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies);
996
997 /**
998 * drm_sched_job_cleanup - clean up scheduler job resources
999 * @job: scheduler job to clean up
1000 *
1001 * Cleans up the resources allocated with drm_sched_job_init().
1002 *
1003 * Drivers should call this from their error unwind code if @job is aborted
1004 * before drm_sched_job_arm() is called.
1005 *
1006 * After that point of no return @job is committed to be executed by the
1007 * scheduler, and this function should be called from the
1008 * &drm_sched_backend_ops.free_job callback.
1009 */
drm_sched_job_cleanup(struct drm_sched_job * job)1010 void drm_sched_job_cleanup(struct drm_sched_job *job)
1011 {
1012 struct dma_fence *fence;
1013 unsigned long index;
1014
1015 if (kref_read(&job->s_fence->finished.refcount)) {
1016 /* drm_sched_job_arm() has been called */
1017 dma_fence_put(&job->s_fence->finished);
1018 } else {
1019 /* aborted job before committing to run it */
1020 drm_sched_fence_free(job->s_fence);
1021 }
1022
1023 job->s_fence = NULL;
1024
1025 xa_for_each(&job->dependencies, index, fence) {
1026 dma_fence_put(fence);
1027 }
1028 xa_destroy(&job->dependencies);
1029
1030 }
1031 EXPORT_SYMBOL(drm_sched_job_cleanup);
1032
1033 /**
1034 * drm_sched_wakeup - Wake up the scheduler if it is ready to queue
1035 * @sched: scheduler instance
1036 *
1037 * Wake up the scheduler if we can queue jobs.
1038 */
drm_sched_wakeup(struct drm_gpu_scheduler * sched)1039 void drm_sched_wakeup(struct drm_gpu_scheduler *sched)
1040 {
1041 drm_sched_run_job_queue(sched);
1042 }
1043
1044 /**
1045 * drm_sched_select_entity - Select next entity to process
1046 *
1047 * @sched: scheduler instance
1048 *
1049 * Return an entity to process or NULL if none are found.
1050 *
1051 * Note, that we break out of the for-loop when "entity" is non-null, which can
1052 * also be an error-pointer--this assures we don't process lower priority
1053 * run-queues. See comments in the respectively called functions.
1054 */
1055 static struct drm_sched_entity *
drm_sched_select_entity(struct drm_gpu_scheduler * sched)1056 drm_sched_select_entity(struct drm_gpu_scheduler *sched)
1057 {
1058 struct drm_sched_entity *entity;
1059 int i;
1060
1061 /* Start with the highest priority.
1062 */
1063 for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {
1064 entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ?
1065 drm_sched_rq_select_entity_fifo(sched, sched->sched_rq[i]) :
1066 drm_sched_rq_select_entity_rr(sched, sched->sched_rq[i]);
1067 if (entity)
1068 break;
1069 }
1070
1071 return IS_ERR(entity) ? NULL : entity;
1072 }
1073
1074 /**
1075 * drm_sched_get_finished_job - fetch the next finished job to be destroyed
1076 *
1077 * @sched: scheduler instance
1078 *
1079 * Returns the next finished job from the pending list (if there is one)
1080 * ready for it to be destroyed.
1081 */
1082 static struct drm_sched_job *
drm_sched_get_finished_job(struct drm_gpu_scheduler * sched)1083 drm_sched_get_finished_job(struct drm_gpu_scheduler *sched)
1084 {
1085 struct drm_sched_job *job, *next;
1086
1087 spin_lock(&sched->job_list_lock);
1088
1089 job = list_first_entry_or_null(&sched->pending_list,
1090 struct drm_sched_job, list);
1091
1092 if (job && dma_fence_is_signaled(&job->s_fence->finished)) {
1093 /* remove job from pending_list */
1094 list_del_init(&job->list);
1095
1096 /* cancel this job's TO timer */
1097 cancel_delayed_work(&sched->work_tdr);
1098 /* make the scheduled timestamp more accurate */
1099 next = list_first_entry_or_null(&sched->pending_list,
1100 typeof(*next), list);
1101
1102 if (next) {
1103 if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT,
1104 &next->s_fence->scheduled.flags))
1105 next->s_fence->scheduled.timestamp =
1106 dma_fence_timestamp(&job->s_fence->finished);
1107 /* start TO timer for next job */
1108 drm_sched_start_timeout(sched);
1109 }
1110 } else {
1111 job = NULL;
1112 }
1113
1114 spin_unlock(&sched->job_list_lock);
1115
1116 return job;
1117 }
1118
1119 /**
1120 * drm_sched_pick_best - Get a drm sched from a sched_list with the least load
1121 * @sched_list: list of drm_gpu_schedulers
1122 * @num_sched_list: number of drm_gpu_schedulers in the sched_list
1123 *
1124 * Returns pointer of the sched with the least load or NULL if none of the
1125 * drm_gpu_schedulers are ready
1126 */
1127 struct drm_gpu_scheduler *
drm_sched_pick_best(struct drm_gpu_scheduler ** sched_list,unsigned int num_sched_list)1128 drm_sched_pick_best(struct drm_gpu_scheduler **sched_list,
1129 unsigned int num_sched_list)
1130 {
1131 struct drm_gpu_scheduler *sched, *picked_sched = NULL;
1132 int i;
1133 unsigned int min_score = UINT_MAX, num_score;
1134
1135 for (i = 0; i < num_sched_list; ++i) {
1136 sched = sched_list[i];
1137
1138 if (!sched->ready) {
1139 DRM_WARN("scheduler %s is not ready, skipping",
1140 sched->name);
1141 continue;
1142 }
1143
1144 num_score = atomic_read(sched->score);
1145 if (num_score < min_score) {
1146 min_score = num_score;
1147 picked_sched = sched;
1148 }
1149 }
1150
1151 return picked_sched;
1152 }
1153 EXPORT_SYMBOL(drm_sched_pick_best);
1154
1155 /**
1156 * drm_sched_free_job_work - worker to call free_job
1157 *
1158 * @w: free job work
1159 */
drm_sched_free_job_work(struct work_struct * w)1160 static void drm_sched_free_job_work(struct work_struct *w)
1161 {
1162 struct drm_gpu_scheduler *sched =
1163 container_of(w, struct drm_gpu_scheduler, work_free_job);
1164 struct drm_sched_job *job;
1165
1166 if (READ_ONCE(sched->pause_submit))
1167 return;
1168
1169 job = drm_sched_get_finished_job(sched);
1170 if (job)
1171 sched->ops->free_job(job);
1172
1173 drm_sched_run_free_queue(sched);
1174 drm_sched_run_job_queue(sched);
1175 }
1176
1177 /**
1178 * drm_sched_run_job_work - worker to call run_job
1179 *
1180 * @w: run job work
1181 */
drm_sched_run_job_work(struct work_struct * w)1182 static void drm_sched_run_job_work(struct work_struct *w)
1183 {
1184 struct drm_gpu_scheduler *sched =
1185 container_of(w, struct drm_gpu_scheduler, work_run_job);
1186 struct drm_sched_entity *entity;
1187 struct dma_fence *fence;
1188 struct drm_sched_fence *s_fence;
1189 struct drm_sched_job *sched_job;
1190 int r;
1191
1192 if (READ_ONCE(sched->pause_submit))
1193 return;
1194
1195 /* Find entity with a ready job */
1196 entity = drm_sched_select_entity(sched);
1197 if (!entity)
1198 return; /* No more work */
1199
1200 sched_job = drm_sched_entity_pop_job(entity);
1201 if (!sched_job) {
1202 complete_all(&entity->entity_idle);
1203 drm_sched_run_job_queue(sched);
1204 return;
1205 }
1206
1207 s_fence = sched_job->s_fence;
1208
1209 atomic_add(sched_job->credits, &sched->credit_count);
1210 drm_sched_job_begin(sched_job);
1211
1212 trace_drm_run_job(sched_job, entity);
1213 fence = sched->ops->run_job(sched_job);
1214 complete_all(&entity->entity_idle);
1215 drm_sched_fence_scheduled(s_fence, fence);
1216
1217 if (!IS_ERR_OR_NULL(fence)) {
1218 /* Drop for original kref_init of the fence */
1219 dma_fence_put(fence);
1220
1221 r = dma_fence_add_callback(fence, &sched_job->cb,
1222 drm_sched_job_done_cb);
1223 if (r == -ENOENT)
1224 drm_sched_job_done(sched_job, fence->error);
1225 else if (r)
1226 DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", r);
1227 } else {
1228 drm_sched_job_done(sched_job, IS_ERR(fence) ?
1229 PTR_ERR(fence) : 0);
1230 }
1231
1232 wake_up(&sched->job_scheduled);
1233 drm_sched_run_job_queue(sched);
1234 }
1235
1236 /**
1237 * drm_sched_init - Init a gpu scheduler instance
1238 *
1239 * @sched: scheduler instance
1240 * @ops: backend operations for this scheduler
1241 * @submit_wq: workqueue to use for submission. If NULL, an ordered wq is
1242 * allocated and used
1243 * @num_rqs: number of runqueues, one for each priority, up to DRM_SCHED_PRIORITY_COUNT
1244 * @credit_limit: the number of credits this scheduler can hold from all jobs
1245 * @hang_limit: number of times to allow a job to hang before dropping it
1246 * @timeout: timeout value in jiffies for the scheduler
1247 * @timeout_wq: workqueue to use for timeout work. If NULL, the system_wq is
1248 * used
1249 * @score: optional score atomic shared with other schedulers
1250 * @name: name used for debugging
1251 * @dev: target &struct device
1252 *
1253 * Return 0 on success, otherwise error code.
1254 */
drm_sched_init(struct drm_gpu_scheduler * sched,const struct drm_sched_backend_ops * ops,struct workqueue_struct * submit_wq,u32 num_rqs,u32 credit_limit,unsigned int hang_limit,long timeout,struct workqueue_struct * timeout_wq,atomic_t * score,const char * name,struct device * dev)1255 int drm_sched_init(struct drm_gpu_scheduler *sched,
1256 const struct drm_sched_backend_ops *ops,
1257 struct workqueue_struct *submit_wq,
1258 u32 num_rqs, u32 credit_limit, unsigned int hang_limit,
1259 long timeout, struct workqueue_struct *timeout_wq,
1260 atomic_t *score, const char *name, struct device *dev)
1261 {
1262 int i;
1263
1264 sched->ops = ops;
1265 sched->credit_limit = credit_limit;
1266 sched->name = name;
1267 sched->timeout = timeout;
1268 sched->timeout_wq = timeout_wq ? : system_wq;
1269 sched->hang_limit = hang_limit;
1270 sched->score = score ? score : &sched->_score;
1271 sched->dev = dev;
1272
1273 if (num_rqs > DRM_SCHED_PRIORITY_COUNT) {
1274 /* This is a gross violation--tell drivers what the problem is.
1275 */
1276 drm_err(sched, "%s: num_rqs cannot be greater than DRM_SCHED_PRIORITY_COUNT\n",
1277 __func__);
1278 return -EINVAL;
1279 } else if (sched->sched_rq) {
1280 /* Not an error, but warn anyway so drivers can
1281 * fine-tune their DRM calling order, and return all
1282 * is good.
1283 */
1284 drm_warn(sched, "%s: scheduler already initialized!\n", __func__);
1285 return 0;
1286 }
1287
1288 if (submit_wq) {
1289 sched->submit_wq = submit_wq;
1290 sched->own_submit_wq = false;
1291 } else {
1292 #ifdef CONFIG_LOCKDEP
1293 sched->submit_wq = alloc_ordered_workqueue_lockdep_map(name,
1294 WQ_MEM_RECLAIM,
1295 &drm_sched_lockdep_map);
1296 #else
1297 sched->submit_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
1298 #endif
1299 if (!sched->submit_wq)
1300 return -ENOMEM;
1301
1302 sched->own_submit_wq = true;
1303 }
1304
1305 sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq),
1306 GFP_KERNEL | __GFP_ZERO);
1307 if (!sched->sched_rq)
1308 goto Out_check_own;
1309 sched->num_rqs = num_rqs;
1310 for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {
1311 sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL);
1312 if (!sched->sched_rq[i])
1313 goto Out_unroll;
1314 drm_sched_rq_init(sched, sched->sched_rq[i]);
1315 }
1316
1317 init_waitqueue_head(&sched->job_scheduled);
1318 INIT_LIST_HEAD(&sched->pending_list);
1319 mtx_init(&sched->job_list_lock, IPL_NONE);
1320 atomic_set(&sched->credit_count, 0);
1321 INIT_DELAYED_WORK(&sched->work_tdr, drm_sched_job_timedout);
1322 INIT_WORK(&sched->work_run_job, drm_sched_run_job_work);
1323 INIT_WORK(&sched->work_free_job, drm_sched_free_job_work);
1324 atomic_set(&sched->_score, 0);
1325 atomic64_set(&sched->job_id_count, 0);
1326 sched->pause_submit = false;
1327
1328 sched->ready = true;
1329 return 0;
1330 Out_unroll:
1331 for (--i ; i >= DRM_SCHED_PRIORITY_KERNEL; i--)
1332 kfree(sched->sched_rq[i]);
1333
1334 kfree(sched->sched_rq);
1335 sched->sched_rq = NULL;
1336 Out_check_own:
1337 if (sched->own_submit_wq)
1338 destroy_workqueue(sched->submit_wq);
1339 drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__);
1340 return -ENOMEM;
1341 }
1342 EXPORT_SYMBOL(drm_sched_init);
1343
1344 /**
1345 * drm_sched_fini - Destroy a gpu scheduler
1346 *
1347 * @sched: scheduler instance
1348 *
1349 * Tears down and cleans up the scheduler.
1350 */
drm_sched_fini(struct drm_gpu_scheduler * sched)1351 void drm_sched_fini(struct drm_gpu_scheduler *sched)
1352 {
1353 struct drm_sched_entity *s_entity;
1354 int i;
1355
1356 drm_sched_wqueue_stop(sched);
1357
1358 for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {
1359 struct drm_sched_rq *rq = sched->sched_rq[i];
1360
1361 spin_lock(&rq->lock);
1362 list_for_each_entry(s_entity, &rq->entities, list)
1363 /*
1364 * Prevents reinsertion and marks job_queue as idle,
1365 * it will removed from rq in drm_sched_entity_fini
1366 * eventually
1367 */
1368 s_entity->stopped = true;
1369 spin_unlock(&rq->lock);
1370 kfree(sched->sched_rq[i]);
1371 }
1372
1373 /* Wakeup everyone stuck in drm_sched_entity_flush for this scheduler */
1374 wake_up_all(&sched->job_scheduled);
1375
1376 /* Confirm no work left behind accessing device structures */
1377 cancel_delayed_work_sync(&sched->work_tdr);
1378
1379 if (sched->own_submit_wq)
1380 destroy_workqueue(sched->submit_wq);
1381 sched->ready = false;
1382 kfree(sched->sched_rq);
1383 sched->sched_rq = NULL;
1384 }
1385 EXPORT_SYMBOL(drm_sched_fini);
1386
1387 /**
1388 * drm_sched_increase_karma - Update sched_entity guilty flag
1389 *
1390 * @bad: The job guilty of time out
1391 *
1392 * Increment on every hang caused by the 'bad' job. If this exceeds the hang
1393 * limit of the scheduler then the respective sched entity is marked guilty and
1394 * jobs from it will not be scheduled further
1395 */
drm_sched_increase_karma(struct drm_sched_job * bad)1396 void drm_sched_increase_karma(struct drm_sched_job *bad)
1397 {
1398 int i;
1399 struct drm_sched_entity *tmp;
1400 struct drm_sched_entity *entity;
1401 struct drm_gpu_scheduler *sched = bad->sched;
1402
1403 /* don't change @bad's karma if it's from KERNEL RQ,
1404 * because sometimes GPU hang would cause kernel jobs (like VM updating jobs)
1405 * corrupt but keep in mind that kernel jobs always considered good.
1406 */
1407 if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
1408 atomic_inc(&bad->karma);
1409
1410 for (i = DRM_SCHED_PRIORITY_HIGH; i < sched->num_rqs; i++) {
1411 struct drm_sched_rq *rq = sched->sched_rq[i];
1412
1413 spin_lock(&rq->lock);
1414 list_for_each_entry_safe(entity, tmp, &rq->entities, list) {
1415 if (bad->s_fence->scheduled.context ==
1416 entity->fence_context) {
1417 if (entity->guilty)
1418 atomic_set(entity->guilty, 1);
1419 break;
1420 }
1421 }
1422 spin_unlock(&rq->lock);
1423 if (&entity->list != &rq->entities)
1424 break;
1425 }
1426 }
1427 }
1428 EXPORT_SYMBOL(drm_sched_increase_karma);
1429
1430 /**
1431 * drm_sched_wqueue_ready - Is the scheduler ready for submission
1432 *
1433 * @sched: scheduler instance
1434 *
1435 * Returns true if submission is ready
1436 */
drm_sched_wqueue_ready(struct drm_gpu_scheduler * sched)1437 bool drm_sched_wqueue_ready(struct drm_gpu_scheduler *sched)
1438 {
1439 return sched->ready;
1440 }
1441 EXPORT_SYMBOL(drm_sched_wqueue_ready);
1442
1443 /**
1444 * drm_sched_wqueue_stop - stop scheduler submission
1445 *
1446 * @sched: scheduler instance
1447 */
drm_sched_wqueue_stop(struct drm_gpu_scheduler * sched)1448 void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched)
1449 {
1450 WRITE_ONCE(sched->pause_submit, true);
1451 cancel_work_sync(&sched->work_run_job);
1452 cancel_work_sync(&sched->work_free_job);
1453 }
1454 EXPORT_SYMBOL(drm_sched_wqueue_stop);
1455
1456 /**
1457 * drm_sched_wqueue_start - start scheduler submission
1458 *
1459 * @sched: scheduler instance
1460 */
drm_sched_wqueue_start(struct drm_gpu_scheduler * sched)1461 void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched)
1462 {
1463 WRITE_ONCE(sched->pause_submit, false);
1464 queue_work(sched->submit_wq, &sched->work_run_job);
1465 queue_work(sched->submit_wq, &sched->work_free_job);
1466 }
1467 EXPORT_SYMBOL(drm_sched_wqueue_start);
1468