aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c')
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.c155
1 files changed, 78 insertions, 77 deletions
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
index 9259f1b6664c..3697eeeecf82 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
@@ -27,6 +27,9 @@
27#include <drm/drmP.h> 27#include <drm/drmP.h>
28#include "gpu_scheduler.h" 28#include "gpu_scheduler.h"
29 29
30#define CREATE_TRACE_POINTS
31#include "gpu_sched_trace.h"
32
30static struct amd_sched_job * 33static struct amd_sched_job *
31amd_sched_entity_pop_job(struct amd_sched_entity *entity); 34amd_sched_entity_pop_job(struct amd_sched_entity *entity);
32static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); 35static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);
@@ -65,29 +68,29 @@ static struct amd_sched_job *
65amd_sched_rq_select_job(struct amd_sched_rq *rq) 68amd_sched_rq_select_job(struct amd_sched_rq *rq)
66{ 69{
67 struct amd_sched_entity *entity; 70 struct amd_sched_entity *entity;
68 struct amd_sched_job *job; 71 struct amd_sched_job *sched_job;
69 72
70 spin_lock(&rq->lock); 73 spin_lock(&rq->lock);
71 74
72 entity = rq->current_entity; 75 entity = rq->current_entity;
73 if (entity) { 76 if (entity) {
74 list_for_each_entry_continue(entity, &rq->entities, list) { 77 list_for_each_entry_continue(entity, &rq->entities, list) {
75 job = amd_sched_entity_pop_job(entity); 78 sched_job = amd_sched_entity_pop_job(entity);
76 if (job) { 79 if (sched_job) {
77 rq->current_entity = entity; 80 rq->current_entity = entity;
78 spin_unlock(&rq->lock); 81 spin_unlock(&rq->lock);
79 return job; 82 return sched_job;
80 } 83 }
81 } 84 }
82 } 85 }
83 86
84 list_for_each_entry(entity, &rq->entities, list) { 87 list_for_each_entry(entity, &rq->entities, list) {
85 88
86 job = amd_sched_entity_pop_job(entity); 89 sched_job = amd_sched_entity_pop_job(entity);
87 if (job) { 90 if (sched_job) {
88 rq->current_entity = entity; 91 rq->current_entity = entity;
89 spin_unlock(&rq->lock); 92 spin_unlock(&rq->lock);
90 return job; 93 return sched_job;
91 } 94 }
92 95
93 if (entity == rq->current_entity) 96 if (entity == rq->current_entity)
@@ -115,23 +118,27 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
115 struct amd_sched_rq *rq, 118 struct amd_sched_rq *rq,
116 uint32_t jobs) 119 uint32_t jobs)
117{ 120{
121 int r;
122
118 if (!(sched && entity && rq)) 123 if (!(sched && entity && rq))
119 return -EINVAL; 124 return -EINVAL;
120 125
121 memset(entity, 0, sizeof(struct amd_sched_entity)); 126 memset(entity, 0, sizeof(struct amd_sched_entity));
122 entity->belongto_rq = rq; 127 INIT_LIST_HEAD(&entity->list);
123 entity->scheduler = sched; 128 entity->rq = rq;
124 entity->fence_context = fence_context_alloc(1); 129 entity->sched = sched;
125 if(kfifo_alloc(&entity->job_queue,
126 jobs * sizeof(void *),
127 GFP_KERNEL))
128 return -EINVAL;
129 130
130 spin_lock_init(&entity->queue_lock); 131 spin_lock_init(&entity->queue_lock);
132 r = kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL);
133 if (r)
134 return r;
135
131 atomic_set(&entity->fence_seq, 0); 136 atomic_set(&entity->fence_seq, 0);
137 entity->fence_context = fence_context_alloc(1);
132 138
133 /* Add the entity to the run queue */ 139 /* Add the entity to the run queue */
134 amd_sched_rq_add_entity(rq, entity); 140 amd_sched_rq_add_entity(rq, entity);
141
135 return 0; 142 return 0;
136} 143}
137 144
@@ -146,8 +153,8 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
146static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched, 153static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched,
147 struct amd_sched_entity *entity) 154 struct amd_sched_entity *entity)
148{ 155{
149 return entity->scheduler == sched && 156 return entity->sched == sched &&
150 entity->belongto_rq != NULL; 157 entity->rq != NULL;
151} 158}
152 159
153/** 160/**
@@ -177,7 +184,7 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity)
177void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, 184void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
178 struct amd_sched_entity *entity) 185 struct amd_sched_entity *entity)
179{ 186{
180 struct amd_sched_rq *rq = entity->belongto_rq; 187 struct amd_sched_rq *rq = entity->rq;
181 188
182 if (!amd_sched_entity_is_initialized(sched, entity)) 189 if (!amd_sched_entity_is_initialized(sched, entity))
183 return; 190 return;
@@ -198,22 +205,22 @@ static void amd_sched_entity_wakeup(struct fence *f, struct fence_cb *cb)
198 container_of(cb, struct amd_sched_entity, cb); 205 container_of(cb, struct amd_sched_entity, cb);
199 entity->dependency = NULL; 206 entity->dependency = NULL;
200 fence_put(f); 207 fence_put(f);
201 amd_sched_wakeup(entity->scheduler); 208 amd_sched_wakeup(entity->sched);
202} 209}
203 210
204static struct amd_sched_job * 211static struct amd_sched_job *
205amd_sched_entity_pop_job(struct amd_sched_entity *entity) 212amd_sched_entity_pop_job(struct amd_sched_entity *entity)
206{ 213{
207 struct amd_gpu_scheduler *sched = entity->scheduler; 214 struct amd_gpu_scheduler *sched = entity->sched;
208 struct amd_sched_job *job; 215 struct amd_sched_job *sched_job;
209 216
210 if (ACCESS_ONCE(entity->dependency)) 217 if (ACCESS_ONCE(entity->dependency))
211 return NULL; 218 return NULL;
212 219
213 if (!kfifo_out_peek(&entity->job_queue, &job, sizeof(job))) 220 if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job)))
214 return NULL; 221 return NULL;
215 222
216 while ((entity->dependency = sched->ops->dependency(job))) { 223 while ((entity->dependency = sched->ops->dependency(sched_job))) {
217 224
218 if (fence_add_callback(entity->dependency, &entity->cb, 225 if (fence_add_callback(entity->dependency, &entity->cb,
219 amd_sched_entity_wakeup)) 226 amd_sched_entity_wakeup))
@@ -222,32 +229,33 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity)
222 return NULL; 229 return NULL;
223 } 230 }
224 231
225 return job; 232 return sched_job;
226} 233}
227 234
228/** 235/**
229 * Helper to submit a job to the job queue 236 * Helper to submit a job to the job queue
230 * 237 *
231 * @job The pointer to job required to submit 238 * @sched_job The pointer to job required to submit
232 * 239 *
233 * Returns true if we could submit the job. 240 * Returns true if we could submit the job.
234 */ 241 */
235static bool amd_sched_entity_in(struct amd_sched_job *job) 242static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
236{ 243{
237 struct amd_sched_entity *entity = job->s_entity; 244 struct amd_sched_entity *entity = sched_job->s_entity;
238 bool added, first = false; 245 bool added, first = false;
239 246
240 spin_lock(&entity->queue_lock); 247 spin_lock(&entity->queue_lock);
241 added = kfifo_in(&entity->job_queue, &job, sizeof(job)) == sizeof(job); 248 added = kfifo_in(&entity->job_queue, &sched_job,
249 sizeof(sched_job)) == sizeof(sched_job);
242 250
243 if (added && kfifo_len(&entity->job_queue) == sizeof(job)) 251 if (added && kfifo_len(&entity->job_queue) == sizeof(sched_job))
244 first = true; 252 first = true;
245 253
246 spin_unlock(&entity->queue_lock); 254 spin_unlock(&entity->queue_lock);
247 255
248 /* first job wakes up scheduler */ 256 /* first job wakes up scheduler */
249 if (first) 257 if (first)
250 amd_sched_wakeup(job->sched); 258 amd_sched_wakeup(sched_job->sched);
251 259
252 return added; 260 return added;
253} 261}
@@ -255,7 +263,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *job)
255/** 263/**
256 * Submit a job to the job queue 264 * Submit a job to the job queue
257 * 265 *
258 * @job The pointer to job required to submit 266 * @sched_job The pointer to job required to submit
259 * 267 *
260 * Returns 0 for success, negative error code otherwise. 268 * Returns 0 for success, negative error code otherwise.
261 */ 269 */
@@ -271,9 +279,9 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job)
271 fence_get(&fence->base); 279 fence_get(&fence->base);
272 sched_job->s_fence = fence; 280 sched_job->s_fence = fence;
273 281
274 wait_event(entity->scheduler->job_scheduled, 282 wait_event(entity->sched->job_scheduled,
275 amd_sched_entity_in(sched_job)); 283 amd_sched_entity_in(sched_job));
276 284 trace_amd_sched_job(sched_job);
277 return 0; 285 return 0;
278} 286}
279 287
@@ -301,30 +309,28 @@ static void amd_sched_wakeup(struct amd_gpu_scheduler *sched)
301static struct amd_sched_job * 309static struct amd_sched_job *
302amd_sched_select_job(struct amd_gpu_scheduler *sched) 310amd_sched_select_job(struct amd_gpu_scheduler *sched)
303{ 311{
304 struct amd_sched_job *job; 312 struct amd_sched_job *sched_job;
305 313
306 if (!amd_sched_ready(sched)) 314 if (!amd_sched_ready(sched))
307 return NULL; 315 return NULL;
308 316
309 /* Kernel run queue has higher priority than normal run queue*/ 317 /* Kernel run queue has higher priority than normal run queue*/
310 job = amd_sched_rq_select_job(&sched->kernel_rq); 318 sched_job = amd_sched_rq_select_job(&sched->kernel_rq);
311 if (job == NULL) 319 if (sched_job == NULL)
312 job = amd_sched_rq_select_job(&sched->sched_rq); 320 sched_job = amd_sched_rq_select_job(&sched->sched_rq);
313 321
314 return job; 322 return sched_job;
315} 323}
316 324
317static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) 325static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
318{ 326{
319 struct amd_sched_job *sched_job = 327 struct amd_sched_fence *s_fence =
320 container_of(cb, struct amd_sched_job, cb); 328 container_of(cb, struct amd_sched_fence, cb);
321 struct amd_gpu_scheduler *sched; 329 struct amd_gpu_scheduler *sched = s_fence->sched;
322 330
323 sched = sched_job->sched;
324 amd_sched_fence_signal(sched_job->s_fence);
325 atomic_dec(&sched->hw_rq_count); 331 atomic_dec(&sched->hw_rq_count);
326 fence_put(&sched_job->s_fence->base); 332 amd_sched_fence_signal(s_fence);
327 sched->ops->process_job(sched_job); 333 fence_put(&s_fence->base);
328 wake_up_interruptible(&sched->wake_up_worker); 334 wake_up_interruptible(&sched->wake_up_worker);
329} 335}
330 336
@@ -338,87 +344,82 @@ static int amd_sched_main(void *param)
338 344
339 while (!kthread_should_stop()) { 345 while (!kthread_should_stop()) {
340 struct amd_sched_entity *entity; 346 struct amd_sched_entity *entity;
341 struct amd_sched_job *job; 347 struct amd_sched_fence *s_fence;
348 struct amd_sched_job *sched_job;
342 struct fence *fence; 349 struct fence *fence;
343 350
344 wait_event_interruptible(sched->wake_up_worker, 351 wait_event_interruptible(sched->wake_up_worker,
345 kthread_should_stop() || 352 kthread_should_stop() ||
346 (job = amd_sched_select_job(sched))); 353 (sched_job = amd_sched_select_job(sched)));
347 354
348 if (!job) 355 if (!sched_job)
349 continue; 356 continue;
350 357
351 entity = job->s_entity; 358 entity = sched_job->s_entity;
359 s_fence = sched_job->s_fence;
352 atomic_inc(&sched->hw_rq_count); 360 atomic_inc(&sched->hw_rq_count);
353 fence = sched->ops->run_job(job); 361 fence = sched->ops->run_job(sched_job);
354 if (fence) { 362 if (fence) {
355 r = fence_add_callback(fence, &job->cb, 363 r = fence_add_callback(fence, &s_fence->cb,
356 amd_sched_process_job); 364 amd_sched_process_job);
357 if (r == -ENOENT) 365 if (r == -ENOENT)
358 amd_sched_process_job(fence, &job->cb); 366 amd_sched_process_job(fence, &s_fence->cb);
359 else if (r) 367 else if (r)
360 DRM_ERROR("fence add callback failed (%d)\n", r); 368 DRM_ERROR("fence add callback failed (%d)\n", r);
361 fence_put(fence); 369 fence_put(fence);
370 } else {
371 DRM_ERROR("Failed to run job!\n");
372 amd_sched_process_job(NULL, &s_fence->cb);
362 } 373 }
363 374
364 count = kfifo_out(&entity->job_queue, &job, sizeof(job)); 375 count = kfifo_out(&entity->job_queue, &sched_job,
365 WARN_ON(count != sizeof(job)); 376 sizeof(sched_job));
377 WARN_ON(count != sizeof(sched_job));
366 wake_up(&sched->job_scheduled); 378 wake_up(&sched->job_scheduled);
367 } 379 }
368 return 0; 380 return 0;
369} 381}
370 382
371/** 383/**
372 * Create a gpu scheduler 384 * Init a gpu scheduler instance
373 * 385 *
386 * @sched The pointer to the scheduler
374 * @ops The backend operations for this scheduler. 387 * @ops The backend operations for this scheduler.
375 * @ring The the ring id for the scheduler.
376 * @hw_submissions Number of hw submissions to do. 388 * @hw_submissions Number of hw submissions to do.
389 * @name Name used for debugging
377 * 390 *
378 * Return the pointer to scheduler for success, otherwise return NULL 391 * Return 0 on success, otherwise error code.
379*/ 392*/
380struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, 393int amd_sched_init(struct amd_gpu_scheduler *sched,
381 unsigned ring, unsigned hw_submission, 394 struct amd_sched_backend_ops *ops,
382 void *priv) 395 unsigned hw_submission, const char *name)
383{ 396{
384 struct amd_gpu_scheduler *sched;
385
386 sched = kzalloc(sizeof(struct amd_gpu_scheduler), GFP_KERNEL);
387 if (!sched)
388 return NULL;
389
390 sched->ops = ops; 397 sched->ops = ops;
391 sched->ring_id = ring;
392 sched->hw_submission_limit = hw_submission; 398 sched->hw_submission_limit = hw_submission;
393 sched->priv = priv; 399 sched->name = name;
394 snprintf(sched->name, sizeof(sched->name), "amdgpu[%d]", ring);
395 amd_sched_rq_init(&sched->sched_rq); 400 amd_sched_rq_init(&sched->sched_rq);
396 amd_sched_rq_init(&sched->kernel_rq); 401 amd_sched_rq_init(&sched->kernel_rq);
397 402
398 init_waitqueue_head(&sched->wake_up_worker); 403 init_waitqueue_head(&sched->wake_up_worker);
399 init_waitqueue_head(&sched->job_scheduled); 404 init_waitqueue_head(&sched->job_scheduled);
400 atomic_set(&sched->hw_rq_count, 0); 405 atomic_set(&sched->hw_rq_count, 0);
406
401 /* Each scheduler will run on a seperate kernel thread */ 407 /* Each scheduler will run on a seperate kernel thread */
402 sched->thread = kthread_run(amd_sched_main, sched, sched->name); 408 sched->thread = kthread_run(amd_sched_main, sched, sched->name);
403 if (IS_ERR(sched->thread)) { 409 if (IS_ERR(sched->thread)) {
404 DRM_ERROR("Failed to create scheduler for id %d.\n", ring); 410 DRM_ERROR("Failed to create scheduler for %s.\n", name);
405 kfree(sched); 411 return PTR_ERR(sched->thread);
406 return NULL;
407 } 412 }
408 413
409 return sched; 414 return 0;
410} 415}
411 416
412/** 417/**
413 * Destroy a gpu scheduler 418 * Destroy a gpu scheduler
414 * 419 *
415 * @sched The pointer to the scheduler 420 * @sched The pointer to the scheduler
416 *
417 * return 0 if succeed. -1 if failed.
418 */ 421 */
419int amd_sched_destroy(struct amd_gpu_scheduler *sched) 422void amd_sched_fini(struct amd_gpu_scheduler *sched)
420{ 423{
421 kthread_stop(sched->thread); 424 kthread_stop(sched->thread);
422 kfree(sched);
423 return 0;
424} 425}