Skip to content

Commit f7fe64a

Browse files
mbrost05Luben Tuikov
authored andcommitted
drm/sched: Split free_job into own work item
Rather than call free_job and run_job in same work item have a dedicated work item for each. This aligns with the design and intended use of work queues. v2: - Test for DMA_FENCE_FLAG_TIMESTAMP_BIT before setting timestamp in free_job() work item (Danilo) v3: - Drop forward dec of drm_sched_select_entity (Boris) - Return in drm_sched_run_job_work if entity NULL (Boris) v4: - Replace dequeue with peek and invert logic (Luben) - Wrap to 100 lines (Luben) - Update comments for *_queue / *_queue_if_ready functions (Luben) v5: - Drop peek argument, blindly reinit idle (Luben) - s/drm_sched_free_job_queue_if_ready/drm_sched_free_job_queue_if_done (Luben) - Update work_run_job & work_free_job kernel doc (Luben) v6: - Do not move drm_sched_select_entity in file (Luben) Signed-off-by: Matthew Brost <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Luben Tuikov <[email protected]> Signed-off-by: Luben Tuikov <[email protected]>
1 parent a6149f0 commit f7fe64a

File tree

2 files changed

+101
-49
lines changed

2 files changed

+101
-49
lines changed

drivers/gpu/drm/scheduler/sched_main.c

Lines changed: 98 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,32 @@ static void drm_sched_run_job_queue(struct drm_gpu_scheduler *sched)
265265
queue_work(sched->submit_wq, &sched->work_run_job);
266266
}
267267

268+
/**
269+
* drm_sched_free_job_queue - enqueue free-job work
270+
* @sched: scheduler instance
271+
*/
272+
static void drm_sched_free_job_queue(struct drm_gpu_scheduler *sched)
273+
{
274+
if (!READ_ONCE(sched->pause_submit))
275+
queue_work(sched->submit_wq, &sched->work_free_job);
276+
}
277+
278+
/**
279+
* drm_sched_free_job_queue_if_done - enqueue free-job work if ready
280+
* @sched: scheduler instance
281+
*/
282+
static void drm_sched_free_job_queue_if_done(struct drm_gpu_scheduler *sched)
283+
{
284+
struct drm_sched_job *job;
285+
286+
spin_lock(&sched->job_list_lock);
287+
job = list_first_entry_or_null(&sched->pending_list,
288+
struct drm_sched_job, list);
289+
if (job && dma_fence_is_signaled(&job->s_fence->finished))
290+
drm_sched_free_job_queue(sched);
291+
spin_unlock(&sched->job_list_lock);
292+
}
293+
268294
/**
269295
* drm_sched_job_done - complete a job
270296
* @s_job: pointer to the job which is done
@@ -284,7 +310,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job, int result)
284310
dma_fence_get(&s_fence->finished);
285311
drm_sched_fence_finished(s_fence, result);
286312
dma_fence_put(&s_fence->finished);
287-
drm_sched_run_job_queue(sched);
313+
drm_sched_free_job_queue(sched);
288314
}
289315

290316
/**
@@ -943,8 +969,10 @@ drm_sched_get_cleanup_job(struct drm_gpu_scheduler *sched)
943969
typeof(*next), list);
944970

945971
if (next) {
946-
next->s_fence->scheduled.timestamp =
947-
dma_fence_timestamp(&job->s_fence->finished);
972+
if (test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT,
973+
&next->s_fence->scheduled.flags))
974+
next->s_fence->scheduled.timestamp =
975+
dma_fence_timestamp(&job->s_fence->finished);
948976
/* start TO timer for next job */
949977
drm_sched_start_timeout(sched);
950978
}
@@ -994,7 +1022,40 @@ drm_sched_pick_best(struct drm_gpu_scheduler **sched_list,
9941022
EXPORT_SYMBOL(drm_sched_pick_best);
9951023

9961024
/**
997-
* drm_sched_run_job_work - main scheduler thread
1025+
* drm_sched_run_job_queue_if_ready - enqueue run-job work if ready
1026+
* @sched: scheduler instance
1027+
*/
1028+
static void drm_sched_run_job_queue_if_ready(struct drm_gpu_scheduler *sched)
1029+
{
1030+
if (drm_sched_select_entity(sched))
1031+
drm_sched_run_job_queue(sched);
1032+
}
1033+
1034+
/**
1035+
* drm_sched_free_job_work - worker to call free_job
1036+
*
1037+
* @w: free job work
1038+
*/
1039+
static void drm_sched_free_job_work(struct work_struct *w)
1040+
{
1041+
struct drm_gpu_scheduler *sched =
1042+
container_of(w, struct drm_gpu_scheduler, work_free_job);
1043+
struct drm_sched_job *cleanup_job;
1044+
1045+
if (READ_ONCE(sched->pause_submit))
1046+
return;
1047+
1048+
cleanup_job = drm_sched_get_cleanup_job(sched);
1049+
if (cleanup_job) {
1050+
sched->ops->free_job(cleanup_job);
1051+
1052+
drm_sched_free_job_queue_if_done(sched);
1053+
drm_sched_run_job_queue_if_ready(sched);
1054+
}
1055+
}
1056+
1057+
/**
1058+
* drm_sched_run_job_work - worker to call run_job
9981059
*
9991060
* @w: run job work
10001061
*/
@@ -1003,65 +1064,51 @@ static void drm_sched_run_job_work(struct work_struct *w)
10031064
struct drm_gpu_scheduler *sched =
10041065
container_of(w, struct drm_gpu_scheduler, work_run_job);
10051066
struct drm_sched_entity *entity;
1006-
struct drm_sched_job *cleanup_job;
1067+
struct dma_fence *fence;
1068+
struct drm_sched_fence *s_fence;
1069+
struct drm_sched_job *sched_job;
10071070
int r;
10081071

10091072
if (READ_ONCE(sched->pause_submit))
10101073
return;
10111074

1012-
cleanup_job = drm_sched_get_cleanup_job(sched);
10131075
entity = drm_sched_select_entity(sched);
1076+
if (!entity)
1077+
return;
10141078

1015-
if (!entity && !cleanup_job)
1079+
sched_job = drm_sched_entity_pop_job(entity);
1080+
if (!sched_job) {
1081+
complete_all(&entity->entity_idle);
10161082
return; /* No more work */
1083+
}
10171084

1018-
if (cleanup_job)
1019-
sched->ops->free_job(cleanup_job);
1020-
1021-
if (entity) {
1022-
struct dma_fence *fence;
1023-
struct drm_sched_fence *s_fence;
1024-
struct drm_sched_job *sched_job;
1025-
1026-
sched_job = drm_sched_entity_pop_job(entity);
1027-
if (!sched_job) {
1028-
complete_all(&entity->entity_idle);
1029-
if (!cleanup_job)
1030-
return; /* No more work */
1031-
goto again;
1032-
}
1033-
1034-
s_fence = sched_job->s_fence;
1035-
1036-
atomic_inc(&sched->hw_rq_count);
1037-
drm_sched_job_begin(sched_job);
1085+
s_fence = sched_job->s_fence;
10381086

1039-
trace_drm_run_job(sched_job, entity);
1040-
fence = sched->ops->run_job(sched_job);
1041-
complete_all(&entity->entity_idle);
1042-
drm_sched_fence_scheduled(s_fence, fence);
1087+
atomic_inc(&sched->hw_rq_count);
1088+
drm_sched_job_begin(sched_job);
10431089

1044-
if (!IS_ERR_OR_NULL(fence)) {
1045-
/* Drop for original kref_init of the fence */
1046-
dma_fence_put(fence);
1090+
trace_drm_run_job(sched_job, entity);
1091+
fence = sched->ops->run_job(sched_job);
1092+
complete_all(&entity->entity_idle);
1093+
drm_sched_fence_scheduled(s_fence, fence);
10471094

1048-
r = dma_fence_add_callback(fence, &sched_job->cb,
1049-
drm_sched_job_done_cb);
1050-
if (r == -ENOENT)
1051-
drm_sched_job_done(sched_job, fence->error);
1052-
else if (r)
1053-
DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n",
1054-
r);
1055-
} else {
1056-
drm_sched_job_done(sched_job, IS_ERR(fence) ?
1057-
PTR_ERR(fence) : 0);
1058-
}
1095+
if (!IS_ERR_OR_NULL(fence)) {
1096+
/* Drop for original kref_init of the fence */
1097+
dma_fence_put(fence);
10591098

1060-
wake_up(&sched->job_scheduled);
1099+
r = dma_fence_add_callback(fence, &sched_job->cb,
1100+
drm_sched_job_done_cb);
1101+
if (r == -ENOENT)
1102+
drm_sched_job_done(sched_job, fence->error);
1103+
else if (r)
1104+
DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n", r);
1105+
} else {
1106+
drm_sched_job_done(sched_job, IS_ERR(fence) ?
1107+
PTR_ERR(fence) : 0);
10611108
}
10621109

1063-
again:
1064-
drm_sched_run_job_queue(sched);
1110+
wake_up(&sched->job_scheduled);
1111+
drm_sched_run_job_queue_if_ready(sched);
10651112
}
10661113

10671114
/**
@@ -1145,6 +1192,7 @@ int drm_sched_init(struct drm_gpu_scheduler *sched,
11451192
atomic_set(&sched->hw_rq_count, 0);
11461193
INIT_DELAYED_WORK(&sched->work_tdr, drm_sched_job_timedout);
11471194
INIT_WORK(&sched->work_run_job, drm_sched_run_job_work);
1195+
INIT_WORK(&sched->work_free_job, drm_sched_free_job_work);
11481196
atomic_set(&sched->_score, 0);
11491197
atomic64_set(&sched->job_id_count, 0);
11501198
sched->pause_submit = false;
@@ -1274,6 +1322,7 @@ void drm_sched_wqueue_stop(struct drm_gpu_scheduler *sched)
12741322
{
12751323
WRITE_ONCE(sched->pause_submit, true);
12761324
cancel_work_sync(&sched->work_run_job);
1325+
cancel_work_sync(&sched->work_free_job);
12771326
}
12781327
EXPORT_SYMBOL(drm_sched_wqueue_stop);
12791328

@@ -1286,5 +1335,6 @@ void drm_sched_wqueue_start(struct drm_gpu_scheduler *sched)
12861335
{
12871336
WRITE_ONCE(sched->pause_submit, false);
12881337
queue_work(sched->submit_wq, &sched->work_run_job);
1338+
queue_work(sched->submit_wq, &sched->work_free_job);
12891339
}
12901340
EXPORT_SYMBOL(drm_sched_wqueue_start);

include/drm/gpu_scheduler.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,10 @@ struct drm_sched_backend_ops {
480480
* finished.
481481
* @hw_rq_count: the number of jobs currently in the hardware queue.
482482
* @job_id_count: used to assign unique id to the each job.
483-
* @submit_wq: workqueue used to queue @work_run_job
483+
* @submit_wq: workqueue used to queue @work_run_job and @work_free_job
484484
* @timeout_wq: workqueue used to queue @work_tdr
485485
* @work_run_job: work which calls run_job op of each scheduler.
486+
* @work_free_job: work which calls free_job op of each scheduler.
486487
* @work_tdr: schedules a delayed call to @drm_sched_job_timedout after the
487488
* timeout interval is over.
488489
* @pending_list: the list of jobs which are currently in the job queue.
@@ -512,6 +513,7 @@ struct drm_gpu_scheduler {
512513
struct workqueue_struct *submit_wq;
513514
struct workqueue_struct *timeout_wq;
514515
struct work_struct work_run_job;
516+
struct work_struct work_free_job;
515517
struct delayed_work work_tdr;
516518
struct list_head pending_list;
517519
spinlock_t job_list_lock;

0 commit comments

Comments
 (0)