0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 #include <linux/kthread.h>
0048 #include <linux/wait.h>
0049 #include <linux/sched.h>
0050 #include <linux/completion.h>
0051 #include <linux/dma-resv.h>
0052 #include <uapi/linux/sched/types.h>
0053
0054 #include <drm/drm_print.h>
0055 #include <drm/drm_gem.h>
0056 #include <drm/gpu_scheduler.h>
0057 #include <drm/spsc_queue.h>
0058
0059 #define CREATE_TRACE_POINTS
0060 #include "gpu_scheduler_trace.h"
0061
0062 #define to_drm_sched_job(sched_job) \
0063 container_of((sched_job), struct drm_sched_job, queue_node)
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 static void drm_sched_rq_init(struct drm_gpu_scheduler *sched,
0074 struct drm_sched_rq *rq)
0075 {
0076 spin_lock_init(&rq->lock);
0077 INIT_LIST_HEAD(&rq->entities);
0078 rq->current_entity = NULL;
0079 rq->sched = sched;
0080 }
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 void drm_sched_rq_add_entity(struct drm_sched_rq *rq,
0091 struct drm_sched_entity *entity)
0092 {
0093 if (!list_empty(&entity->list))
0094 return;
0095 spin_lock(&rq->lock);
0096 atomic_inc(rq->sched->score);
0097 list_add_tail(&entity->list, &rq->entities);
0098 spin_unlock(&rq->lock);
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109 void drm_sched_rq_remove_entity(struct drm_sched_rq *rq,
0110 struct drm_sched_entity *entity)
0111 {
0112 if (list_empty(&entity->list))
0113 return;
0114 spin_lock(&rq->lock);
0115 atomic_dec(rq->sched->score);
0116 list_del_init(&entity->list);
0117 if (rq->current_entity == entity)
0118 rq->current_entity = NULL;
0119 spin_unlock(&rq->lock);
0120 }
0121
0122
0123
0124
0125
0126
0127
0128
0129 static struct drm_sched_entity *
0130 drm_sched_rq_select_entity(struct drm_sched_rq *rq)
0131 {
0132 struct drm_sched_entity *entity;
0133
0134 spin_lock(&rq->lock);
0135
0136 entity = rq->current_entity;
0137 if (entity) {
0138 list_for_each_entry_continue(entity, &rq->entities, list) {
0139 if (drm_sched_entity_is_ready(entity)) {
0140 rq->current_entity = entity;
0141 reinit_completion(&entity->entity_idle);
0142 spin_unlock(&rq->lock);
0143 return entity;
0144 }
0145 }
0146 }
0147
0148 list_for_each_entry(entity, &rq->entities, list) {
0149
0150 if (drm_sched_entity_is_ready(entity)) {
0151 rq->current_entity = entity;
0152 reinit_completion(&entity->entity_idle);
0153 spin_unlock(&rq->lock);
0154 return entity;
0155 }
0156
0157 if (entity == rq->current_entity)
0158 break;
0159 }
0160
0161 spin_unlock(&rq->lock);
0162
0163 return NULL;
0164 }
0165
0166
0167
0168
0169
0170
0171
0172 static void drm_sched_job_done(struct drm_sched_job *s_job)
0173 {
0174 struct drm_sched_fence *s_fence = s_job->s_fence;
0175 struct drm_gpu_scheduler *sched = s_fence->sched;
0176
0177 atomic_dec(&sched->hw_rq_count);
0178 atomic_dec(sched->score);
0179
0180 trace_drm_sched_process_job(s_fence);
0181
0182 dma_fence_get(&s_fence->finished);
0183 drm_sched_fence_finished(s_fence);
0184 dma_fence_put(&s_fence->finished);
0185 wake_up_interruptible(&sched->wake_up_worker);
0186 }
0187
0188
0189
0190
0191
0192
0193 static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb)
0194 {
0195 struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb);
0196
0197 drm_sched_job_done(s_job);
0198 }
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208 bool drm_sched_dependency_optimized(struct dma_fence* fence,
0209 struct drm_sched_entity *entity)
0210 {
0211 struct drm_gpu_scheduler *sched = entity->rq->sched;
0212 struct drm_sched_fence *s_fence;
0213
0214 if (!fence || dma_fence_is_signaled(fence))
0215 return false;
0216 if (fence->context == entity->fence_context)
0217 return true;
0218 s_fence = to_drm_sched_fence(fence);
0219 if (s_fence && s_fence->sched == sched)
0220 return true;
0221
0222 return false;
0223 }
0224 EXPORT_SYMBOL(drm_sched_dependency_optimized);
0225
0226
0227
0228
0229
0230
0231
0232
0233 static void drm_sched_start_timeout(struct drm_gpu_scheduler *sched)
0234 {
0235 if (sched->timeout != MAX_SCHEDULE_TIMEOUT &&
0236 !list_empty(&sched->pending_list))
0237 queue_delayed_work(sched->timeout_wq, &sched->work_tdr, sched->timeout);
0238 }
0239
0240
0241
0242
0243
0244
0245
0246
0247 void drm_sched_fault(struct drm_gpu_scheduler *sched)
0248 {
0249 mod_delayed_work(sched->timeout_wq, &sched->work_tdr, 0);
0250 }
0251 EXPORT_SYMBOL(drm_sched_fault);
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 unsigned long drm_sched_suspend_timeout(struct drm_gpu_scheduler *sched)
0266 {
0267 unsigned long sched_timeout, now = jiffies;
0268
0269 sched_timeout = sched->work_tdr.timer.expires;
0270
0271
0272
0273
0274
0275 if (mod_delayed_work(sched->timeout_wq, &sched->work_tdr, MAX_SCHEDULE_TIMEOUT)
0276 && time_after(sched_timeout, now))
0277 return sched_timeout - now;
0278 else
0279 return sched->timeout;
0280 }
0281 EXPORT_SYMBOL(drm_sched_suspend_timeout);
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291 void drm_sched_resume_timeout(struct drm_gpu_scheduler *sched,
0292 unsigned long remaining)
0293 {
0294 spin_lock(&sched->job_list_lock);
0295
0296 if (list_empty(&sched->pending_list))
0297 cancel_delayed_work(&sched->work_tdr);
0298 else
0299 mod_delayed_work(sched->timeout_wq, &sched->work_tdr, remaining);
0300
0301 spin_unlock(&sched->job_list_lock);
0302 }
0303 EXPORT_SYMBOL(drm_sched_resume_timeout);
0304
0305 static void drm_sched_job_begin(struct drm_sched_job *s_job)
0306 {
0307 struct drm_gpu_scheduler *sched = s_job->sched;
0308
0309 spin_lock(&sched->job_list_lock);
0310 list_add_tail(&s_job->list, &sched->pending_list);
0311 drm_sched_start_timeout(sched);
0312 spin_unlock(&sched->job_list_lock);
0313 }
0314
0315 static void drm_sched_job_timedout(struct work_struct *work)
0316 {
0317 struct drm_gpu_scheduler *sched;
0318 struct drm_sched_job *job;
0319 enum drm_gpu_sched_stat status = DRM_GPU_SCHED_STAT_NOMINAL;
0320
0321 sched = container_of(work, struct drm_gpu_scheduler, work_tdr.work);
0322
0323
0324 spin_lock(&sched->job_list_lock);
0325 job = list_first_entry_or_null(&sched->pending_list,
0326 struct drm_sched_job, list);
0327
0328 if (job) {
0329
0330
0331
0332
0333
0334 list_del_init(&job->list);
0335 spin_unlock(&sched->job_list_lock);
0336
0337 status = job->sched->ops->timedout_job(job);
0338
0339
0340
0341
0342
0343 if (sched->free_guilty) {
0344 job->sched->ops->free_job(job);
0345 sched->free_guilty = false;
0346 }
0347 } else {
0348 spin_unlock(&sched->job_list_lock);
0349 }
0350
0351 if (status != DRM_GPU_SCHED_STAT_ENODEV) {
0352 spin_lock(&sched->job_list_lock);
0353 drm_sched_start_timeout(sched);
0354 spin_unlock(&sched->job_list_lock);
0355 }
0356 }
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367 void drm_sched_increase_karma(struct drm_sched_job *bad)
0368 {
0369 drm_sched_increase_karma_ext(bad, 1);
0370 }
0371 EXPORT_SYMBOL(drm_sched_increase_karma);
0372
0373 void drm_sched_reset_karma(struct drm_sched_job *bad)
0374 {
0375 drm_sched_increase_karma_ext(bad, 0);
0376 }
0377 EXPORT_SYMBOL(drm_sched_reset_karma);
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391 void drm_sched_stop(struct drm_gpu_scheduler *sched, struct drm_sched_job *bad)
0392 {
0393 struct drm_sched_job *s_job, *tmp;
0394
0395 kthread_park(sched->thread);
0396
0397
0398
0399
0400
0401
0402
0403
0404 if (bad && bad->sched == sched)
0405
0406
0407
0408
0409 list_add(&bad->list, &sched->pending_list);
0410
0411
0412
0413
0414
0415
0416
0417 list_for_each_entry_safe_reverse(s_job, tmp, &sched->pending_list,
0418 list) {
0419 if (s_job->s_fence->parent &&
0420 dma_fence_remove_callback(s_job->s_fence->parent,
0421 &s_job->cb)) {
0422 dma_fence_put(s_job->s_fence->parent);
0423 s_job->s_fence->parent = NULL;
0424 atomic_dec(&sched->hw_rq_count);
0425 } else {
0426
0427
0428
0429
0430 spin_lock(&sched->job_list_lock);
0431 list_del_init(&s_job->list);
0432 spin_unlock(&sched->job_list_lock);
0433
0434
0435
0436
0437
0438
0439
0440 dma_fence_wait(&s_job->s_fence->finished, false);
0441
0442
0443
0444
0445
0446
0447 if (bad != s_job)
0448 sched->ops->free_job(s_job);
0449 else
0450 sched->free_guilty = true;
0451 }
0452 }
0453
0454
0455
0456
0457
0458
0459
0460 cancel_delayed_work(&sched->work_tdr);
0461 }
0462
0463 EXPORT_SYMBOL(drm_sched_stop);
0464
0465
0466
0467
0468
0469
0470
0471
0472 void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery)
0473 {
0474 struct drm_sched_job *s_job, *tmp;
0475 int r;
0476
0477
0478
0479
0480
0481
0482 list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
0483 struct dma_fence *fence = s_job->s_fence->parent;
0484
0485 atomic_inc(&sched->hw_rq_count);
0486
0487 if (!full_recovery)
0488 continue;
0489
0490 if (fence) {
0491 r = dma_fence_add_callback(fence, &s_job->cb,
0492 drm_sched_job_done_cb);
0493 if (r == -ENOENT)
0494 drm_sched_job_done(s_job);
0495 else if (r)
0496 DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n",
0497 r);
0498 } else
0499 drm_sched_job_done(s_job);
0500 }
0501
0502 if (full_recovery) {
0503 spin_lock(&sched->job_list_lock);
0504 drm_sched_start_timeout(sched);
0505 spin_unlock(&sched->job_list_lock);
0506 }
0507
0508 kthread_unpark(sched->thread);
0509 }
0510 EXPORT_SYMBOL(drm_sched_start);
0511
0512
0513
0514
0515
0516
0517
0518 void drm_sched_resubmit_jobs(struct drm_gpu_scheduler *sched)
0519 {
0520 drm_sched_resubmit_jobs_ext(sched, INT_MAX);
0521 }
0522 EXPORT_SYMBOL(drm_sched_resubmit_jobs);
0523
0524
0525
0526
0527
0528
0529
0530
0531 void drm_sched_resubmit_jobs_ext(struct drm_gpu_scheduler *sched, int max)
0532 {
0533 struct drm_sched_job *s_job, *tmp;
0534 uint64_t guilty_context;
0535 bool found_guilty = false;
0536 struct dma_fence *fence;
0537 int i = 0;
0538
0539 list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
0540 struct drm_sched_fence *s_fence = s_job->s_fence;
0541
0542 if (i >= max)
0543 break;
0544
0545 if (!found_guilty && atomic_read(&s_job->karma) > sched->hang_limit) {
0546 found_guilty = true;
0547 guilty_context = s_job->s_fence->scheduled.context;
0548 }
0549
0550 if (found_guilty && s_job->s_fence->scheduled.context == guilty_context)
0551 dma_fence_set_error(&s_fence->finished, -ECANCELED);
0552
0553 fence = sched->ops->run_job(s_job);
0554 i++;
0555
0556 if (IS_ERR_OR_NULL(fence)) {
0557 if (IS_ERR(fence))
0558 dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
0559
0560 s_job->s_fence->parent = NULL;
0561 } else {
0562
0563 s_job->s_fence->parent = dma_fence_get(fence);
0564
0565
0566 dma_fence_put(fence);
0567 }
0568 }
0569 }
0570 EXPORT_SYMBOL(drm_sched_resubmit_jobs_ext);
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591 int drm_sched_job_init(struct drm_sched_job *job,
0592 struct drm_sched_entity *entity,
0593 void *owner)
0594 {
0595 drm_sched_entity_select_rq(entity);
0596 if (!entity->rq)
0597 return -ENOENT;
0598
0599 job->entity = entity;
0600 job->s_fence = drm_sched_fence_alloc(entity, owner);
0601 if (!job->s_fence)
0602 return -ENOMEM;
0603
0604 INIT_LIST_HEAD(&job->list);
0605
0606 xa_init_flags(&job->dependencies, XA_FLAGS_ALLOC);
0607
0608 return 0;
0609 }
0610 EXPORT_SYMBOL(drm_sched_job_init);
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625 void drm_sched_job_arm(struct drm_sched_job *job)
0626 {
0627 struct drm_gpu_scheduler *sched;
0628 struct drm_sched_entity *entity = job->entity;
0629
0630 BUG_ON(!entity);
0631
0632 sched = entity->rq->sched;
0633
0634 job->sched = sched;
0635 job->s_priority = entity->rq - sched->sched_rq;
0636 job->id = atomic64_inc_return(&sched->job_id_count);
0637
0638 drm_sched_fence_init(job->s_fence, job->entity);
0639 }
0640 EXPORT_SYMBOL(drm_sched_job_arm);
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652 int drm_sched_job_add_dependency(struct drm_sched_job *job,
0653 struct dma_fence *fence)
0654 {
0655 struct dma_fence *entry;
0656 unsigned long index;
0657 u32 id = 0;
0658 int ret;
0659
0660 if (!fence)
0661 return 0;
0662
0663
0664
0665
0666
0667 xa_for_each(&job->dependencies, index, entry) {
0668 if (entry->context != fence->context)
0669 continue;
0670
0671 if (dma_fence_is_later(fence, entry)) {
0672 dma_fence_put(entry);
0673 xa_store(&job->dependencies, index, fence, GFP_KERNEL);
0674 } else {
0675 dma_fence_put(fence);
0676 }
0677 return 0;
0678 }
0679
0680 ret = xa_alloc(&job->dependencies, &id, fence, xa_limit_32b, GFP_KERNEL);
0681 if (ret != 0)
0682 dma_fence_put(fence);
0683
0684 return ret;
0685 }
0686 EXPORT_SYMBOL(drm_sched_job_add_dependency);
0687
0688
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703 int drm_sched_job_add_implicit_dependencies(struct drm_sched_job *job,
0704 struct drm_gem_object *obj,
0705 bool write)
0706 {
0707 struct dma_resv_iter cursor;
0708 struct dma_fence *fence;
0709 int ret;
0710
0711 dma_resv_assert_held(obj->resv);
0712
0713 dma_resv_for_each_fence(&cursor, obj->resv, dma_resv_usage_rw(write),
0714 fence) {
0715
0716 dma_fence_get(fence);
0717 ret = drm_sched_job_add_dependency(job, fence);
0718 if (ret) {
0719 dma_fence_put(fence);
0720 return ret;
0721 }
0722 }
0723 return 0;
0724 }
0725 EXPORT_SYMBOL(drm_sched_job_add_implicit_dependencies);
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741 void drm_sched_job_cleanup(struct drm_sched_job *job)
0742 {
0743 struct dma_fence *fence;
0744 unsigned long index;
0745
0746 if (kref_read(&job->s_fence->finished.refcount)) {
0747
0748 dma_fence_put(&job->s_fence->finished);
0749 } else {
0750
0751 drm_sched_fence_free(job->s_fence);
0752 }
0753
0754 job->s_fence = NULL;
0755
0756 xa_for_each(&job->dependencies, index, fence) {
0757 dma_fence_put(fence);
0758 }
0759 xa_destroy(&job->dependencies);
0760
0761 }
0762 EXPORT_SYMBOL(drm_sched_job_cleanup);
0763
0764
0765
0766
0767
0768
0769
0770
0771 static bool drm_sched_ready(struct drm_gpu_scheduler *sched)
0772 {
0773 return atomic_read(&sched->hw_rq_count) <
0774 sched->hw_submission_limit;
0775 }
0776
0777
0778
0779
0780
0781
0782
0783 void drm_sched_wakeup(struct drm_gpu_scheduler *sched)
0784 {
0785 if (drm_sched_ready(sched))
0786 wake_up_interruptible(&sched->wake_up_worker);
0787 }
0788
0789
0790
0791
0792
0793
0794
0795
0796 static struct drm_sched_entity *
0797 drm_sched_select_entity(struct drm_gpu_scheduler *sched)
0798 {
0799 struct drm_sched_entity *entity;
0800 int i;
0801
0802 if (!drm_sched_ready(sched))
0803 return NULL;
0804
0805
0806 for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
0807 entity = drm_sched_rq_select_entity(&sched->sched_rq[i]);
0808 if (entity)
0809 break;
0810 }
0811
0812 return entity;
0813 }
0814
0815
0816
0817
0818
0819
0820
0821
0822
0823 static struct drm_sched_job *
0824 drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
0825 {
0826 struct drm_sched_job *job, *next;
0827
0828 spin_lock(&sched->job_list_lock);
0829
0830 job = list_first_entry_or_null(&sched->pending_list,
0831 struct drm_sched_job, list);
0832
0833 if (job && dma_fence_is_signaled(&job->s_fence->finished)) {
0834
0835 list_del_init(&job->list);
0836
0837
0838 cancel_delayed_work(&sched->work_tdr);
0839
0840 next = list_first_entry_or_null(&sched->pending_list,
0841 typeof(*next), list);
0842
0843 if (next) {
0844 next->s_fence->scheduled.timestamp =
0845 job->s_fence->finished.timestamp;
0846
0847 drm_sched_start_timeout(sched);
0848 }
0849 } else {
0850 job = NULL;
0851 }
0852
0853 spin_unlock(&sched->job_list_lock);
0854
0855 return job;
0856 }
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866 struct drm_gpu_scheduler *
0867 drm_sched_pick_best(struct drm_gpu_scheduler **sched_list,
0868 unsigned int num_sched_list)
0869 {
0870 struct drm_gpu_scheduler *sched, *picked_sched = NULL;
0871 int i;
0872 unsigned int min_score = UINT_MAX, num_score;
0873
0874 for (i = 0; i < num_sched_list; ++i) {
0875 sched = sched_list[i];
0876
0877 if (!sched->ready) {
0878 DRM_WARN("scheduler %s is not ready, skipping",
0879 sched->name);
0880 continue;
0881 }
0882
0883 num_score = atomic_read(sched->score);
0884 if (num_score < min_score) {
0885 min_score = num_score;
0886 picked_sched = sched;
0887 }
0888 }
0889
0890 return picked_sched;
0891 }
0892 EXPORT_SYMBOL(drm_sched_pick_best);
0893
0894
0895
0896
0897
0898
0899
0900
0901 static bool drm_sched_blocked(struct drm_gpu_scheduler *sched)
0902 {
0903 if (kthread_should_park()) {
0904 kthread_parkme();
0905 return true;
0906 }
0907
0908 return false;
0909 }
0910
0911
0912
0913
0914
0915
0916
0917
0918 static int drm_sched_main(void *param)
0919 {
0920 struct drm_gpu_scheduler *sched = (struct drm_gpu_scheduler *)param;
0921 int r;
0922
0923 sched_set_fifo_low(current);
0924
0925 while (!kthread_should_stop()) {
0926 struct drm_sched_entity *entity = NULL;
0927 struct drm_sched_fence *s_fence;
0928 struct drm_sched_job *sched_job;
0929 struct dma_fence *fence;
0930 struct drm_sched_job *cleanup_job = NULL;
0931
0932 wait_event_interruptible(sched->wake_up_worker,
0933 (cleanup_job = drm_sched_get_cleanup_job(sched)) ||
0934 (!drm_sched_blocked(sched) &&
0935 (entity = drm_sched_select_entity(sched))) ||
0936 kthread_should_stop());
0937
0938 if (cleanup_job)
0939 sched->ops->free_job(cleanup_job);
0940
0941 if (!entity)
0942 continue;
0943
0944 sched_job = drm_sched_entity_pop_job(entity);
0945
0946 if (!sched_job) {
0947 complete(&entity->entity_idle);
0948 continue;
0949 }
0950
0951 s_fence = sched_job->s_fence;
0952
0953 atomic_inc(&sched->hw_rq_count);
0954 drm_sched_job_begin(sched_job);
0955
0956 trace_drm_run_job(sched_job, entity);
0957 fence = sched->ops->run_job(sched_job);
0958 complete(&entity->entity_idle);
0959 drm_sched_fence_scheduled(s_fence);
0960
0961 if (!IS_ERR_OR_NULL(fence)) {
0962 s_fence->parent = dma_fence_get(fence);
0963
0964 dma_fence_put(fence);
0965
0966 r = dma_fence_add_callback(fence, &sched_job->cb,
0967 drm_sched_job_done_cb);
0968 if (r == -ENOENT)
0969 drm_sched_job_done(sched_job);
0970 else if (r)
0971 DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n",
0972 r);
0973 } else {
0974 if (IS_ERR(fence))
0975 dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
0976
0977 drm_sched_job_done(sched_job);
0978 }
0979
0980 wake_up(&sched->job_scheduled);
0981 }
0982 return 0;
0983 }
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000 int drm_sched_init(struct drm_gpu_scheduler *sched,
1001 const struct drm_sched_backend_ops *ops,
1002 unsigned hw_submission, unsigned hang_limit,
1003 long timeout, struct workqueue_struct *timeout_wq,
1004 atomic_t *score, const char *name, struct device *dev)
1005 {
1006 int i, ret;
1007 sched->ops = ops;
1008 sched->hw_submission_limit = hw_submission;
1009 sched->name = name;
1010 sched->timeout = timeout;
1011 sched->timeout_wq = timeout_wq ? : system_wq;
1012 sched->hang_limit = hang_limit;
1013 sched->score = score ? score : &sched->_score;
1014 sched->dev = dev;
1015 for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; i++)
1016 drm_sched_rq_init(sched, &sched->sched_rq[i]);
1017
1018 init_waitqueue_head(&sched->wake_up_worker);
1019 init_waitqueue_head(&sched->job_scheduled);
1020 INIT_LIST_HEAD(&sched->pending_list);
1021 spin_lock_init(&sched->job_list_lock);
1022 atomic_set(&sched->hw_rq_count, 0);
1023 INIT_DELAYED_WORK(&sched->work_tdr, drm_sched_job_timedout);
1024 atomic_set(&sched->_score, 0);
1025 atomic64_set(&sched->job_id_count, 0);
1026
1027
1028 sched->thread = kthread_run(drm_sched_main, sched, sched->name);
1029 if (IS_ERR(sched->thread)) {
1030 ret = PTR_ERR(sched->thread);
1031 sched->thread = NULL;
1032 DRM_DEV_ERROR(sched->dev, "Failed to create scheduler for %s.\n", name);
1033 return ret;
1034 }
1035
1036 sched->ready = true;
1037 return 0;
1038 }
1039 EXPORT_SYMBOL(drm_sched_init);
1040
1041
1042
1043
1044
1045
1046
1047
1048 void drm_sched_fini(struct drm_gpu_scheduler *sched)
1049 {
1050 struct drm_sched_entity *s_entity;
1051 int i;
1052
1053 if (sched->thread)
1054 kthread_stop(sched->thread);
1055
1056 for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
1057 struct drm_sched_rq *rq = &sched->sched_rq[i];
1058
1059 if (!rq)
1060 continue;
1061
1062 spin_lock(&rq->lock);
1063 list_for_each_entry(s_entity, &rq->entities, list)
1064
1065
1066
1067
1068
1069 s_entity->stopped = true;
1070 spin_unlock(&rq->lock);
1071
1072 }
1073
1074
1075 wake_up_all(&sched->job_scheduled);
1076
1077
1078 cancel_delayed_work_sync(&sched->work_tdr);
1079
1080 sched->ready = false;
1081 }
1082 EXPORT_SYMBOL(drm_sched_fini);
1083
1084
1085
1086
1087
1088
1089
1090
1091 void drm_sched_increase_karma_ext(struct drm_sched_job *bad, int type)
1092 {
1093 int i;
1094 struct drm_sched_entity *tmp;
1095 struct drm_sched_entity *entity;
1096 struct drm_gpu_scheduler *sched = bad->sched;
1097
1098
1099
1100
1101
1102 if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
1103 if (type == 0)
1104 atomic_set(&bad->karma, 0);
1105 else if (type == 1)
1106 atomic_inc(&bad->karma);
1107
1108 for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_KERNEL;
1109 i++) {
1110 struct drm_sched_rq *rq = &sched->sched_rq[i];
1111
1112 spin_lock(&rq->lock);
1113 list_for_each_entry_safe(entity, tmp, &rq->entities, list) {
1114 if (bad->s_fence->scheduled.context ==
1115 entity->fence_context) {
1116 if (entity->guilty)
1117 atomic_set(entity->guilty, type);
1118 break;
1119 }
1120 }
1121 spin_unlock(&rq->lock);
1122 if (&entity->list != &rq->entities)
1123 break;
1124 }
1125 }
1126 }
1127 EXPORT_SYMBOL(drm_sched_increase_karma_ext);