diff options
Diffstat (limited to 'drivers/gpu/drm/amd/scheduler/gpu_scheduler.c')
-rw-r--r-- | drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 155 |
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 | |||
30 | static struct amd_sched_job * | 33 | static struct amd_sched_job * |
31 | amd_sched_entity_pop_job(struct amd_sched_entity *entity); | 34 | amd_sched_entity_pop_job(struct amd_sched_entity *entity); |
32 | static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); | 35 | static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); |
@@ -65,29 +68,29 @@ static struct amd_sched_job * | |||
65 | amd_sched_rq_select_job(struct amd_sched_rq *rq) | 68 | amd_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, | |||
146 | static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched, | 153 | static 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) | |||
177 | void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, | 184 | void 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 | ||
204 | static struct amd_sched_job * | 211 | static struct amd_sched_job * |
205 | amd_sched_entity_pop_job(struct amd_sched_entity *entity) | 212 | amd_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 | */ |
235 | static bool amd_sched_entity_in(struct amd_sched_job *job) | 242 | static 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) | |||
301 | static struct amd_sched_job * | 309 | static struct amd_sched_job * |
302 | amd_sched_select_job(struct amd_gpu_scheduler *sched) | 310 | amd_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 | ||
317 | static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) | 325 | static 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 | */ |
380 | struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, | 393 | int 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 | */ |
419 | int amd_sched_destroy(struct amd_gpu_scheduler *sched) | 422 | void 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 | } |