Skip to content

Commit 56e4496

Browse files
author
Luben Tuikov
committed
drm/sched: Convert the GPU scheduler to variable number of run-queues
The GPU scheduler has now a variable number of run-queues, which are set up at drm_sched_init() time. This way, each driver announces how many run-queues it requires (supports) per each GPU scheduler it creates. Note, that run-queues correspond to scheduler "priorities", thus if the number of run-queues is set to 1 at drm_sched_init(), then that scheduler supports a single run-queue, i.e. single "priority". If a driver further sets a single entity per run-queue, then this creates a 1-to-1 correspondence between a scheduler and a scheduled entity. Cc: Lucas Stach <[email protected]> Cc: Russell King <[email protected]> Cc: Qiang Yu <[email protected]> Cc: Rob Clark <[email protected]> Cc: Abhinav Kumar <[email protected]> Cc: Dmitry Baryshkov <[email protected]> Cc: Danilo Krummrich <[email protected]> Cc: Matthew Brost <[email protected]> Cc: Boris Brezillon <[email protected]> Cc: Alex Deucher <[email protected]> Cc: Christian König <[email protected]> Cc: Emma Anholt <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Signed-off-by: Luben Tuikov <[email protected]> Acked-by: Christian König <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3ddba96 commit 56e4496

File tree

11 files changed

+98
-25
lines changed

11 files changed

+98
-25
lines changed

drivers/gpu/drm/amd/amdgpu/amdgpu_device.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,6 +2280,7 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev)
22802280
}
22812281

22822282
r = drm_sched_init(&ring->sched, &amdgpu_sched_ops,
2283+
DRM_SCHED_PRIORITY_COUNT,
22832284
ring->num_hw_submission, 0,
22842285
timeout, adev->reset_domain->wq,
22852286
ring->sched_score, ring->name,

drivers/gpu/drm/amd/amdgpu/amdgpu_job.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,8 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched)
325325
int i;
326326

327327
/* Signal all jobs not yet scheduled */
328-
for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
329-
struct drm_sched_rq *rq = &sched->sched_rq[i];
328+
for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
329+
struct drm_sched_rq *rq = sched->sched_rq[i];
330330
spin_lock(&rq->lock);
331331
list_for_each_entry(s_entity, &rq->entities, list) {
332332
while ((s_job = to_drm_sched_job(spsc_queue_pop(&s_entity->job_queue)))) {

drivers/gpu/drm/etnaviv/etnaviv_sched.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ int etnaviv_sched_init(struct etnaviv_gpu *gpu)
135135
int ret;
136136

137137
ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops,
138+
DRM_SCHED_PRIORITY_COUNT,
138139
etnaviv_hw_jobs_limit, etnaviv_job_hang_limit,
139140
msecs_to_jiffies(500), NULL, NULL,
140141
dev_name(gpu->dev), gpu->dev);

drivers/gpu/drm/lima/lima_sched.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,9 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name)
488488

489489
INIT_WORK(&pipe->recover_work, lima_sched_recover_work);
490490

491-
return drm_sched_init(&pipe->base, &lima_sched_ops, 1,
491+
return drm_sched_init(&pipe->base, &lima_sched_ops,
492+
DRM_SCHED_PRIORITY_COUNT,
493+
1,
492494
lima_job_hang_limit,
493495
msecs_to_jiffies(timeout), NULL,
494496
NULL, name, pipe->ldev->dev);

drivers/gpu/drm/msm/msm_ringbuffer.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id,
9595
sched_timeout = MAX_SCHEDULE_TIMEOUT;
9696

9797
ret = drm_sched_init(&ring->sched, &msm_sched_ops,
98-
num_hw_submissions, 0, sched_timeout,
99-
NULL, NULL, to_msm_bo(ring->bo)->name, gpu->dev->dev);
98+
DRM_SCHED_PRIORITY_COUNT,
99+
num_hw_submissions, 0, sched_timeout,
100+
NULL, NULL, to_msm_bo(ring->bo)->name, gpu->dev->dev);
100101
if (ret) {
101102
goto fail;
102103
}

drivers/gpu/drm/nouveau/nouveau_sched.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ int nouveau_sched_init(struct nouveau_drm *drm)
430430
return -ENOMEM;
431431

432432
return drm_sched_init(sched, &nouveau_sched_ops,
433+
DRM_SCHED_PRIORITY_COUNT,
433434
NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit,
434435
NULL, NULL, "nouveau_sched", drm->dev->dev);
435436
}

drivers/gpu/drm/panfrost/panfrost_job.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,7 @@ int panfrost_job_init(struct panfrost_device *pfdev)
853853

854854
ret = drm_sched_init(&js->queue[j].sched,
855855
&panfrost_sched_ops,
856+
DRM_SCHED_PRIORITY_COUNT,
856857
nentries, 0,
857858
msecs_to_jiffies(JOB_TIMEOUT_MS),
858859
pfdev->reset.wq,

drivers/gpu/drm/scheduler/sched_entity.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,20 @@ int drm_sched_entity_init(struct drm_sched_entity *entity,
7575
RCU_INIT_POINTER(entity->last_scheduled, NULL);
7676
RB_CLEAR_NODE(&entity->rb_tree_node);
7777

78-
if(num_sched_list)
79-
entity->rq = &sched_list[0]->sched_rq[entity->priority];
78+
if (!sched_list[0]->sched_rq) {
79+
/* Warn drivers not to do this and to fix their DRM
80+
* calling order.
81+
*/
82+
pr_warn("%s: called with uninitialized scheduler\n", __func__);
83+
} else if (num_sched_list) {
84+
/* The "priority" of an entity cannot exceed the number
85+
* of run-queues of a scheduler.
86+
*/
87+
if (entity->priority >= sched_list[0]->num_rqs)
88+
entity->priority = max_t(u32, sched_list[0]->num_rqs,
89+
DRM_SCHED_PRIORITY_MIN);
90+
entity->rq = sched_list[0]->sched_rq[entity->priority];
91+
}
8092

8193
init_completion(&entity->entity_idle);
8294

@@ -533,7 +545,7 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity)
533545

534546
spin_lock(&entity->rq_lock);
535547
sched = drm_sched_pick_best(entity->sched_list, entity->num_sched_list);
536-
rq = sched ? &sched->sched_rq[entity->priority] : NULL;
548+
rq = sched ? sched->sched_rq[entity->priority] : NULL;
537549
if (rq != entity->rq) {
538550
drm_sched_rq_remove_entity(entity->rq, entity);
539551
entity->rq = rq;

drivers/gpu/drm/scheduler/sched_main.c

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,14 @@ int drm_sched_job_init(struct drm_sched_job *job,
632632
struct drm_sched_entity *entity,
633633
void *owner)
634634
{
635-
if (!entity->rq)
635+
if (!entity->rq) {
636+
/* This will most likely be followed by missing frames
637+
* or worse--a blank screen--leave a trail in the
638+
* logs, so this can be debugged easier.
639+
*/
640+
drm_err(job->sched, "%s: entity has no rq!\n", __func__);
636641
return -ENOENT;
642+
}
637643

638644
job->entity = entity;
639645
job->s_fence = drm_sched_fence_alloc(entity, owner);
@@ -671,7 +677,7 @@ void drm_sched_job_arm(struct drm_sched_job *job)
671677
sched = entity->rq->sched;
672678

673679
job->sched = sched;
674-
job->s_priority = entity->rq - sched->sched_rq;
680+
job->s_priority = entity->priority;
675681
job->id = atomic64_inc_return(&sched->job_id_count);
676682

677683
drm_sched_fence_init(job->s_fence, job->entity);
@@ -888,10 +894,10 @@ drm_sched_select_entity(struct drm_gpu_scheduler *sched)
888894
return NULL;
889895

890896
/* Kernel run queue has higher priority than normal run queue*/
891-
for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
897+
for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
892898
entity = drm_sched_policy == DRM_SCHED_POLICY_FIFO ?
893-
drm_sched_rq_select_entity_fifo(&sched->sched_rq[i]) :
894-
drm_sched_rq_select_entity_rr(&sched->sched_rq[i]);
899+
drm_sched_rq_select_entity_fifo(sched->sched_rq[i]) :
900+
drm_sched_rq_select_entity_rr(sched->sched_rq[i]);
895901
if (entity)
896902
break;
897903
}
@@ -1071,6 +1077,7 @@ static int drm_sched_main(void *param)
10711077
*
10721078
* @sched: scheduler instance
10731079
* @ops: backend operations for this scheduler
1080+
* @num_rqs: number of runqueues, one for each priority, up to DRM_SCHED_PRIORITY_COUNT
10741081
* @hw_submission: number of hw submissions that can be in flight
10751082
* @hang_limit: number of times to allow a job to hang before dropping it
10761083
* @timeout: timeout value in jiffies for the scheduler
@@ -1084,11 +1091,12 @@ static int drm_sched_main(void *param)
10841091
*/
10851092
int drm_sched_init(struct drm_gpu_scheduler *sched,
10861093
const struct drm_sched_backend_ops *ops,
1087-
unsigned hw_submission, unsigned hang_limit,
1094+
u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit,
10881095
long timeout, struct workqueue_struct *timeout_wq,
10891096
atomic_t *score, const char *name, struct device *dev)
10901097
{
10911098
int i, ret;
1099+
10921100
sched->ops = ops;
10931101
sched->hw_submission_limit = hw_submission;
10941102
sched->name = name;
@@ -1097,8 +1105,36 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
10971105
sched->hang_limit = hang_limit;
10981106
sched->score = score ? score : &sched->_score;
10991107
sched->dev = dev;
1100-
for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_COUNT; i++)
1101-
drm_sched_rq_init(sched, &sched->sched_rq[i]);
1108+
1109+
if (num_rqs > DRM_SCHED_PRIORITY_COUNT) {
1110+
/* This is a gross violation--tell drivers what the problem is.
1111+
*/
1112+
drm_err(sched, "%s: num_rqs cannot be greater than DRM_SCHED_PRIORITY_COUNT\n",
1113+
__func__);
1114+
return -EINVAL;
1115+
} else if (sched->sched_rq) {
1116+
/* Not an error, but warn anyway so drivers can
1117+
* fine-tune their DRM calling order, and return all
1118+
* is good.
1119+
*/
1120+
drm_warn(sched, "%s: scheduler already initialized!\n", __func__);
1121+
return 0;
1122+
}
1123+
1124+
sched->sched_rq = kmalloc_array(num_rqs, sizeof(*sched->sched_rq),
1125+
GFP_KERNEL | __GFP_ZERO);
1126+
if (!sched->sched_rq) {
1127+
drm_err(sched, "%s: out of memory for sched_rq\n", __func__);
1128+
return -ENOMEM;
1129+
}
1130+
sched->num_rqs = num_rqs;
1131+
ret = -ENOMEM;
1132+
for (i = DRM_SCHED_PRIORITY_MIN; i < sched->num_rqs; i++) {
1133+
sched->sched_rq[i] = kzalloc(sizeof(*sched->sched_rq[i]), GFP_KERNEL);
1134+
if (!sched->sched_rq[i])
1135+
goto Out_unroll;
1136+
drm_sched_rq_init(sched, sched->sched_rq[i]);
1137+
}
11021138

11031139
init_waitqueue_head(&sched->wake_up_worker);
11041140
init_waitqueue_head(&sched->job_scheduled);
@@ -1115,11 +1151,18 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
11151151
ret = PTR_ERR(sched->thread);
11161152
sched->thread = NULL;
11171153
DRM_DEV_ERROR(sched->dev, "Failed to create scheduler for %s.\n", name);
1118-
return ret;
1154+
goto Out_unroll;
11191155
}
11201156

11211157
sched->ready = true;
11221158
return 0;
1159+
Out_unroll:
1160+
for (--i ; i >= DRM_SCHED_PRIORITY_MIN; i--)
1161+
kfree(sched->sched_rq[i]);
1162+
kfree(sched->sched_rq);
1163+
sched->sched_rq = NULL;
1164+
drm_err(sched, "%s: Failed to setup GPU scheduler--out of memory\n", __func__);
1165+
return ret;
11231166
}
11241167
EXPORT_SYMBOL(drm_sched_init);
11251168

@@ -1138,8 +1181,8 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
11381181
if (sched->thread)
11391182
kthread_stop(sched->thread);
11401183

1141-
for (i = DRM_SCHED_PRIORITY_COUNT - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
1142-
struct drm_sched_rq *rq = &sched->sched_rq[i];
1184+
for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) {
1185+
struct drm_sched_rq *rq = sched->sched_rq[i];
11431186

11441187
spin_lock(&rq->lock);
11451188
list_for_each_entry(s_entity, &rq->entities, list)
@@ -1150,7 +1193,7 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
11501193
*/
11511194
s_entity->stopped = true;
11521195
spin_unlock(&rq->lock);
1153-
1196+
kfree(sched->sched_rq[i]);
11541197
}
11551198

11561199
/* Wakeup everyone stuck in drm_sched_entity_flush for this scheduler */
@@ -1160,6 +1203,8 @@ void drm_sched_fini(struct drm_gpu_scheduler *sched)
11601203
cancel_delayed_work_sync(&sched->work_tdr);
11611204

11621205
sched->ready = false;
1206+
kfree(sched->sched_rq);
1207+
sched->sched_rq = NULL;
11631208
}
11641209
EXPORT_SYMBOL(drm_sched_fini);
11651210

@@ -1186,9 +1231,10 @@ void drm_sched_increase_karma(struct drm_sched_job *bad)
11861231
if (bad->s_priority != DRM_SCHED_PRIORITY_KERNEL) {
11871232
atomic_inc(&bad->karma);
11881233

1189-
for (i = DRM_SCHED_PRIORITY_MIN; i < DRM_SCHED_PRIORITY_KERNEL;
1234+
for (i = DRM_SCHED_PRIORITY_MIN;
1235+
i < min_t(typeof(sched->num_rqs), sched->num_rqs, DRM_SCHED_PRIORITY_KERNEL);
11901236
i++) {
1191-
struct drm_sched_rq *rq = &sched->sched_rq[i];
1237+
struct drm_sched_rq *rq = sched->sched_rq[i];
11921238

11931239
spin_lock(&rq->lock);
11941240
list_for_each_entry_safe(entity, tmp, &rq->entities, list) {

drivers/gpu/drm/v3d/v3d_sched.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ v3d_sched_init(struct v3d_dev *v3d)
389389

390390
ret = drm_sched_init(&v3d->queue[V3D_BIN].sched,
391391
&v3d_bin_sched_ops,
392+
DRM_SCHED_PRIORITY_COUNT,
392393
hw_jobs_limit, job_hang_limit,
393394
msecs_to_jiffies(hang_limit_ms), NULL,
394395
NULL, "v3d_bin", v3d->drm.dev);
@@ -397,6 +398,7 @@ v3d_sched_init(struct v3d_dev *v3d)
397398

398399
ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
399400
&v3d_render_sched_ops,
401+
DRM_SCHED_PRIORITY_COUNT,
400402
hw_jobs_limit, job_hang_limit,
401403
msecs_to_jiffies(hang_limit_ms), NULL,
402404
NULL, "v3d_render", v3d->drm.dev);
@@ -405,6 +407,7 @@ v3d_sched_init(struct v3d_dev *v3d)
405407

406408
ret = drm_sched_init(&v3d->queue[V3D_TFU].sched,
407409
&v3d_tfu_sched_ops,
410+
DRM_SCHED_PRIORITY_COUNT,
408411
hw_jobs_limit, job_hang_limit,
409412
msecs_to_jiffies(hang_limit_ms), NULL,
410413
NULL, "v3d_tfu", v3d->drm.dev);
@@ -414,6 +417,7 @@ v3d_sched_init(struct v3d_dev *v3d)
414417
if (v3d_has_csd(v3d)) {
415418
ret = drm_sched_init(&v3d->queue[V3D_CSD].sched,
416419
&v3d_csd_sched_ops,
420+
DRM_SCHED_PRIORITY_COUNT,
417421
hw_jobs_limit, job_hang_limit,
418422
msecs_to_jiffies(hang_limit_ms), NULL,
419423
NULL, "v3d_csd", v3d->drm.dev);
@@ -422,6 +426,7 @@ v3d_sched_init(struct v3d_dev *v3d)
422426

423427
ret = drm_sched_init(&v3d->queue[V3D_CACHE_CLEAN].sched,
424428
&v3d_cache_clean_sched_ops,
429+
DRM_SCHED_PRIORITY_COUNT,
425430
hw_jobs_limit, job_hang_limit,
426431
msecs_to_jiffies(hang_limit_ms), NULL,
427432
NULL, "v3d_cache_clean", v3d->drm.dev);

include/drm/gpu_scheduler.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,9 @@ struct drm_sched_backend_ops {
472472
* @hw_submission_limit: the max size of the hardware queue.
473473
* @timeout: the time after which a job is removed from the scheduler.
474474
* @name: name of the ring for which this scheduler is being used.
475-
* @sched_rq: priority wise array of run queues.
475+
* @num_rqs: Number of run-queues. This is at most DRM_SCHED_PRIORITY_COUNT,
476+
* as there's usually one run-queue per priority, but could be less.
477+
* @sched_rq: An allocated array of run-queues of size @num_rqs;
476478
* @wake_up_worker: the wait queue on which the scheduler sleeps until a job
477479
* is ready to be scheduled.
478480
* @job_scheduled: once @drm_sched_entity_do_release is called the scheduler
@@ -501,7 +503,8 @@ struct drm_gpu_scheduler {
501503
uint32_t hw_submission_limit;
502504
long timeout;
503505
const char *name;
504-
struct drm_sched_rq sched_rq[DRM_SCHED_PRIORITY_COUNT];
506+
u32 num_rqs;
507+
struct drm_sched_rq **sched_rq;
505508
wait_queue_head_t wake_up_worker;
506509
wait_queue_head_t job_scheduled;
507510
atomic_t hw_rq_count;
@@ -521,7 +524,7 @@ struct drm_gpu_scheduler {
521524

522525
int drm_sched_init(struct drm_gpu_scheduler *sched,
523526
const struct drm_sched_backend_ops *ops,
524-
uint32_t hw_submission, unsigned hang_limit,
527+
u32 num_rqs, uint32_t hw_submission, unsigned int hang_limit,
525528
long timeout, struct workqueue_struct *timeout_wq,
526529
atomic_t *score, const char *name, struct device *dev);
527530

0 commit comments

Comments
 (0)