History

drm/v3d: Refactor job management.

The CL submission had two jobs embedded in an exec struct. When I added TFU support, I had to replicate some of the exec stuff and some of the job stuff. As I went to add CSD, it became clear that actually what was in exec should just be in the two CL jobs, and it would let us share a lot more code between the 4 queues. v2: Fix missing error path in TFU ioctl's bo[] allocation.

Eric Anholt committed 7 years ago

Commit a783a091 parent d4c30224 files · +380 −329Browse files

Unified · Split

4 files
  1. drivers/gpu/drm/v3d/v3d_drv.h +39 −38
  2. drivers/gpu/drm/v3d/v3d_gem.c +186 −179
  3. drivers/gpu/drm/v3d/v3d_irq.c +4 −4
  4. drivers/gpu/drm/v3d/v3d_sched.c +151 −108
drivers/gpu/drm/v3d/v3d_drv.h+39−38
@@ -67,8 +67,8 @@ struct v3d_dev { · 66 unmodified lines
67 67
68 struct work_struct overflow_mem_work;68 struct work_struct overflow_mem_work;
69 69
70 struct v3d_exec_info *bin_job;70 struct v3d_bin_job *bin_job;
71 struct v3d_exec_info *render_job;71 struct v3d_render_job *render_job;
72 struct v3d_tfu_job *tfu_job;72 struct v3d_tfu_job *tfu_job;
73 73
74 struct v3d_queue_state queue[V3D_MAX_QUEUES];74 struct v3d_queue_state queue[V3D_MAX_QUEUES];
@@ -117,7 +117,7 @@ struct v3d_bo { · 42 unmodified lines
117 struct drm_mm_node node;117 struct drm_mm_node node;
118 118
119 /* List entry for the BO's position in119 /* List entry for the BO's position in
120 * v3d_exec_info->unref_list120 * v3d_render_job->unref_list
121 */121 */
122 struct list_head unref_head;122 struct list_head unref_head;
123};123};
@@ -157,7 +157,15 @@ to_v3d_fence(struct dma_fence *fence) · 33 unmodified lines
157struct v3d_job {157struct v3d_job {
158 struct drm_sched_job base;158 struct drm_sched_job base;
159 159
160 struct v3d_exec_info *exec;160 struct kref refcount;
161
162 struct v3d_dev *v3d;
163
164 /* This is the array of BOs that were looked up at the start
165 * of submission.
166 */
167 struct drm_gem_object **bo;
168 u32 bo_count;
161 169
162 /* An optional fence userspace can pass in for the job to depend on. */170 /* An optional fence userspace can pass in for the job to depend on. */
163 struct dma_fence *in_fence;171 struct dma_fence *in_fence;
@@ -165,59 +173,53 @@ struct v3d_job { · 1 unmodified line
165 /* v3d fence to be signaled by IRQ handler when the job is complete. */173 /* v3d fence to be signaled by IRQ handler when the job is complete. */
166 struct dma_fence *irq_fence;174 struct dma_fence *irq_fence;
167 175
176 /* scheduler fence for when the job is considered complete and
177 * the BO reservations can be released.
178 */
179 struct dma_fence *done_fence;
180
181 /* Callback for the freeing of the job on refcount going to 0. */
182 void (*free)(struct kref *ref);
183};
184
185struct v3d_bin_job {
186 struct v3d_job base;
187
168 /* GPU virtual addresses of the start/end of the CL job. */188 /* GPU virtual addresses of the start/end of the CL job. */
169 u32 start, end;189 u32 start, end;
170 190
171 u32 timedout_ctca, timedout_ctra;191 u32 timedout_ctca, timedout_ctra;
172};
173 192
174struct v3d_exec_info {193 /* Corresponding render job, for attaching our overflow memory. */
175 struct v3d_dev *v3d;194 struct v3d_render_job *render;
195
196 /* Submitted tile memory allocation start/size, tile state. */
197 u32 qma, qms, qts;
198};
176 199
177 struct v3d_job bin, render;200struct v3d_render_job {
201 struct v3d_job base;
178 202
179 /* Fence for when the scheduler considers the binner to be203 /* Optional fence for the binner, to depend on before starting
180 * done, for render to depend on.204 * our job.
181 */205 */
182 struct dma_fence *bin_done_fence;206 struct dma_fence *bin_done_fence;
183 207
184 /* Fence for when the scheduler considers the render to be208 /* GPU virtual addresses of the start/end of the CL job. */
185 * done, for when the BOs reservations should be complete.209 u32 start, end;
186 */
187 struct dma_fence *render_done_fence;
188
189 struct kref refcount;
190 210
191 /* This is the array of BOs that were looked up at the start of exec. */211 u32 timedout_ctca, timedout_ctra;
192 struct drm_gem_object **bo;
193 u32 bo_count;
194 212
195 /* List of overflow BOs used in the job that need to be213 /* List of overflow BOs used in the job that need to be
196 * released once the job is complete.214 * released once the job is complete.
197 */215 */
198 struct list_head unref_list;216 struct list_head unref_list;
199
200 /* Submitted tile memory allocation start/size, tile state. */
201 u32 qma, qms, qts;
202};217};
203 218
204struct v3d_tfu_job {219struct v3d_tfu_job {
205 struct drm_sched_job base;220 struct v3d_job base;
206 221
207 struct drm_v3d_submit_tfu args;222 struct drm_v3d_submit_tfu args;
208
209 /* An optional fence userspace can pass in for the job to depend on. */
210 struct dma_fence *in_fence;
211
212 /* v3d fence to be signaled by IRQ handler when the job is complete. */
213 struct dma_fence *irq_fence;
214
215 struct v3d_dev *v3d;
216
217 struct kref refcount;
218
219 /* This is the array of BOs that were looked up at the start of exec. */
220 struct drm_gem_object *bo[4];
221};223};
222 224
223/**225/**
@@ -283,8 +285,7 @@ int v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, · 59 unmodified lines
283 struct drm_file *file_priv);285 struct drm_file *file_priv);
284int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,286int v3d_wait_bo_ioctl(struct drm_device *dev, void *data,
285 struct drm_file *file_priv);287 struct drm_file *file_priv);
286void v3d_exec_put(struct v3d_exec_info *exec);288void v3d_job_put(struct v3d_job *job);
287void v3d_tfu_job_put(struct v3d_tfu_job *exec);
288void v3d_reset(struct v3d_dev *v3d);289void v3d_reset(struct v3d_dev *v3d);
289void v3d_invalidate_caches(struct v3d_dev *v3d);290void v3d_invalidate_caches(struct v3d_dev *v3d);
290 291
drivers/gpu/drm/v3d/v3d_gem.c+186−179
@@ -193,18 +193,6 @@ v3d_invalidate_caches(struct v3d_dev *v3d) · 192 unmodified lines
193 v3d_invalidate_slices(v3d, 0);193 v3d_invalidate_slices(v3d, 0);
194}194}
195 195
196static void
197v3d_attach_object_fences(struct drm_gem_object **bos, int bo_count,
198 struct dma_fence *fence)
199{
200 int i;
201
202 for (i = 0; i < bo_count; i++) {
203 /* XXX: Use shared fences for read-only objects. */
204 reservation_object_add_excl_fence(bos[i]->resv, fence);
205 }
206}
207
208/* Takes the reservation lock on all the BOs being referenced, so that196/* Takes the reservation lock on all the BOs being referenced, so that
209 * at queue submit time we can update the reservations.197 * at queue submit time we can update the reservations.
210 *198 *
@@ -239,11 +227,11 @@ v3d_lock_bo_reservations(struct drm_gem_object **bos, · 28 unmodified lines
239}227}
240 228
241/**229/**
242 * v3d_cl_lookup_bos() - Sets up exec->bo[] with the GEM objects230 * v3d_lookup_bos() - Sets up job->bo[] with the GEM objects
243 * referenced by the job.231 * referenced by the job.
244 * @dev: DRM device232 * @dev: DRM device
245 * @file_priv: DRM file for this fd233 * @file_priv: DRM file for this fd
246 * @exec: V3D job being set up234 * @job: V3D job being set up
247 *235 *
248 * The command validator needs to reference BOs by their index within236 * The command validator needs to reference BOs by their index within
249 * the submitted job's BO list. This does the validation of the job's237 * the submitted job's BO list. This does the validation of the job's
@@ -253,18 +241,19 @@ v3d_lock_bo_reservations(struct drm_gem_object **bos, · 3 unmodified lines
253 * failure, because that will happen at v3d_exec_cleanup() time.241 * failure, because that will happen at v3d_exec_cleanup() time.
254 */242 */
255static int243static int
256v3d_cl_lookup_bos(struct drm_device *dev,244v3d_lookup_bos(struct drm_device *dev,
257 struct drm_file *file_priv,245 struct drm_file *file_priv,
258 struct drm_v3d_submit_cl *args,246 struct v3d_job *job,
259 struct v3d_exec_info *exec)247 u64 bo_handles,
248 u32 bo_count)
260{249{
261 u32 *handles;250 u32 *handles;
262 int ret = 0;251 int ret = 0;
263 int i;252 int i;
264 253
265 exec->bo_count = args->bo_handle_count;254 job->bo_count = bo_count;
266 255
267 if (!exec->bo_count) {256 if (!job->bo_count) {
268 /* See comment on bo_index for why we have to check257 /* See comment on bo_index for why we have to check
269 * this.258 * this.
270 */259 */
@@ -272,15 +261,15 @@ v3d_cl_lookup_bos(struct drm_device *dev, · 1 unmodified line
272 return -EINVAL;261 return -EINVAL;
273 }262 }
274 263
275 exec->bo = kvmalloc_array(exec->bo_count,264 job->bo = kvmalloc_array(job->bo_count,
276 sizeof(struct drm_gem_cma_object *),265 sizeof(struct drm_gem_cma_object *),
277 GFP_KERNEL | __GFP_ZERO);266 GFP_KERNEL | __GFP_ZERO);
278 if (!exec->bo) {267 if (!job->bo) {
279 DRM_DEBUG("Failed to allocate validated BO pointers\n");268 DRM_DEBUG("Failed to allocate validated BO pointers\n");
280 return -ENOMEM;269 return -ENOMEM;
281 }270 }
282 271
283 handles = kvmalloc_array(exec->bo_count, sizeof(u32), GFP_KERNEL);272 handles = kvmalloc_array(job->bo_count, sizeof(u32), GFP_KERNEL);
284 if (!handles) {273 if (!handles) {
285 ret = -ENOMEM;274 ret = -ENOMEM;
286 DRM_DEBUG("Failed to allocate incoming GEM handles\n");275 DRM_DEBUG("Failed to allocate incoming GEM handles\n");
@@ -288,15 +277,15 @@ v3d_cl_lookup_bos(struct drm_device *dev, · 1 unmodified line
288 }277 }
289 278
290 if (copy_from_user(handles,279 if (copy_from_user(handles,
291 (void __user *)(uintptr_t)args->bo_handles,280 (void __user *)(uintptr_t)bo_handles,
292 exec->bo_count * sizeof(u32))) {281 job->bo_count * sizeof(u32))) {
293 ret = -EFAULT;282 ret = -EFAULT;
294 DRM_DEBUG("Failed to copy in GEM handles\n");283 DRM_DEBUG("Failed to copy in GEM handles\n");
295 goto fail;284 goto fail;
296 }285 }
297 286
298 spin_lock(&file_priv->table_lock);287 spin_lock(&file_priv->table_lock);
299 for (i = 0; i < exec->bo_count; i++) {288 for (i = 0; i < job->bo_count; i++) {
300 struct drm_gem_object *bo = idr_find(&file_priv->object_idr,289 struct drm_gem_object *bo = idr_find(&file_priv->object_idr,
301 handles[i]);290 handles[i]);
302 if (!bo) {291 if (!bo) {
@@ -307,7 +296,7 @@ v3d_cl_lookup_bos(struct drm_device *dev, · 4 unmodified lines
307 goto fail;296 goto fail;
308 }297 }
309 drm_gem_object_get(bo);298 drm_gem_object_get(bo);
310 exec->bo[i] = bo;299 job->bo[i] = bo;
311 }300 }
312 spin_unlock(&file_priv->table_lock);301 spin_unlock(&file_priv->table_lock);
313 302
@@ -317,67 +306,44 @@ fail: · 3 unmodified lines
317}306}
318 307
319static void308static void
320v3d_exec_cleanup(struct kref *ref)309v3d_job_free(struct kref *ref)
321{310{
322 struct v3d_exec_info *exec = container_of(ref, struct v3d_exec_info,311 struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
323 refcount);312 int i;
324 struct v3d_dev *v3d = exec->v3d;
325 unsigned int i;
326 struct v3d_bo *bo, *save;
327
328 dma_fence_put(exec->bin.in_fence);
329 dma_fence_put(exec->render.in_fence);
330
331 dma_fence_put(exec->bin.irq_fence);
332 dma_fence_put(exec->render.irq_fence);
333
334 dma_fence_put(exec->bin_done_fence);
335 dma_fence_put(exec->render_done_fence);
336
337 for (i = 0; i < exec->bo_count; i++)
338 drm_gem_object_put_unlocked(exec->bo[i]);
339 kvfree(exec->bo);
340 313
341 list_for_each_entry_safe(bo, save, &exec->unref_list, unref_head) {314 for (i = 0; i < job->bo_count; i++) {
342 drm_gem_object_put_unlocked(&bo->base.base);315 if (job->bo[i])
316 drm_gem_object_put_unlocked(job->bo[i]);
343 }317 }
318 kvfree(job->bo);
344 319
345 pm_runtime_mark_last_busy(v3d->dev);320 dma_fence_put(job->in_fence);
346 pm_runtime_put_autosuspend(v3d->dev);321 dma_fence_put(job->irq_fence);
322 dma_fence_put(job->done_fence);
347 323
348 kfree(exec);324 pm_runtime_mark_last_busy(job->v3d->dev);
349}325 pm_runtime_put_autosuspend(job->v3d->dev);
350 326
351void v3d_exec_put(struct v3d_exec_info *exec)327 kfree(job);
352{
353 kref_put(&exec->refcount, v3d_exec_cleanup);
354}328}
355 329
356static void330static void
357v3d_tfu_job_cleanup(struct kref *ref)331v3d_render_job_free(struct kref *ref)
358{332{
359 struct v3d_tfu_job *job = container_of(ref, struct v3d_tfu_job,333 struct v3d_render_job *job = container_of(ref, struct v3d_render_job,
360 refcount);334 base.refcount);
361 struct v3d_dev *v3d = job->v3d;335 struct v3d_bo *bo, *save;
362 unsigned int i;
363
364 dma_fence_put(job->in_fence);
365 dma_fence_put(job->irq_fence);
366 336
367 for (i = 0; i < ARRAY_SIZE(job->bo); i++) {337 list_for_each_entry_safe(bo, save, &job->unref_list, unref_head) {
368 if (job->bo[i])338 drm_gem_object_put_unlocked(&bo->base.base);
369 drm_gem_object_put_unlocked(job->bo[i]);
370 }339 }
371 340
372 pm_runtime_mark_last_busy(v3d->dev);341 v3d_job_free(ref);
373 pm_runtime_put_autosuspend(v3d->dev);
374
375 kfree(job);
376}342}
377 343
378void v3d_tfu_job_put(struct v3d_tfu_job *job)344void v3d_job_put(struct v3d_job *job)
379{345{
380 kref_put(&job->refcount, v3d_tfu_job_cleanup);346 kref_put(&job->refcount, job->free);
381}347}
382 348
383int349int
@@ -413,6 +379,77 @@ v3d_wait_bo_ioctl(struct drm_device *dev, void *data, · 29 unmodified lines
413 return ret;379 return ret;
414}380}
415 381
382static int
383v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
384 struct v3d_job *job, void (*free)(struct kref *ref),
385 u32 in_sync)
386{
387 int ret;
388
389 job->v3d = v3d;
390 job->free = free;
391
392 ret = pm_runtime_get_sync(v3d->dev);
393 if (ret < 0)
394 return ret;
395
396 ret = drm_syncobj_find_fence(file_priv, in_sync, 0, 0, &job->in_fence);
397 if (ret == -EINVAL) {
398 pm_runtime_put_autosuspend(v3d->dev);
399 return ret;
400 }
401
402 kref_init(&job->refcount);
403
404 return 0;
405}
406
407static int
408v3d_push_job(struct v3d_file_priv *v3d_priv,
409 struct v3d_job *job, enum v3d_queue queue)
410{
411 int ret;
412
413 ret = drm_sched_job_init(&job->base, &v3d_priv->sched_entity[queue],
414 v3d_priv);
415 if (ret)
416 return ret;
417
418 job->done_fence = dma_fence_get(&job->base.s_fence->finished);
419
420 /* put by scheduler job completion */
421 kref_get(&job->refcount);
422
423 drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[queue]);
424
425 return 0;
426}
427
428static void
429v3d_attach_fences_and_unlock_reservation(struct drm_file *file_priv,
430 struct v3d_job *job,
431 struct ww_acquire_ctx *acquire_ctx,
432 u32 out_sync)
433{
434 struct drm_syncobj *sync_out;
435 int i;
436
437 for (i = 0; i < job->bo_count; i++) {
438 /* XXX: Use shared fences for read-only objects. */
439 reservation_object_add_excl_fence(job->bo[i]->resv,
440 job->done_fence);
441 }
442
443 drm_gem_unlock_reservations(job->bo, job->bo_count, acquire_ctx);
444
445 /* Update the return sync object for the job */
446 sync_out = drm_syncobj_find(file_priv, out_sync);
447 if (sync_out) {
448 drm_syncobj_replace_fence(sync_out, job->done_fence);
449 drm_syncobj_put(sync_out);
450 }
451}
452
416/**453/**
417 * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D.454 * v3d_submit_cl_ioctl() - Submits a job (frame) to the V3D.
418 * @dev: DRM device455 * @dev: DRM device
@@ -432,9 +469,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 13 unmodified lines
432 struct v3d_dev *v3d = to_v3d_dev(dev);469 struct v3d_dev *v3d = to_v3d_dev(dev);
433 struct v3d_file_priv *v3d_priv = file_priv->driver_priv;470 struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
434 struct drm_v3d_submit_cl *args = data;471 struct drm_v3d_submit_cl *args = data;
435 struct v3d_exec_info *exec;472 struct v3d_bin_job *bin = NULL;
473 struct v3d_render_job *render;
436 struct ww_acquire_ctx acquire_ctx;474 struct ww_acquire_ctx acquire_ctx;
437 struct drm_syncobj *sync_out;
438 int ret = 0;475 int ret = 0;
439 476
440 trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);477 trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
@@ -444,100 +481,83 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data, · 3 unmodified lines
444 return -EINVAL;481 return -EINVAL;
445 }482 }
446 483
447 exec = kcalloc(1, sizeof(*exec), GFP_KERNEL);484 render = kcalloc(1, sizeof(*render), GFP_KERNEL);
448 if (!exec)485 if (!render)
449 return -ENOMEM;486 return -ENOMEM;
450 487
451 ret = pm_runtime_get_sync(v3d->dev);488 render->start = args->rcl_start;
452 if (ret < 0) {489 render->end = args->rcl_end;
453 kfree(exec);490 INIT_LIST_HEAD(&render->unref_list);
491
492 ret = v3d_job_init(v3d, file_priv, &render->base,
493 v3d_render_job_free, args->in_sync_rcl);
494 if (ret) {
495 kfree(render);
454 return ret;496 return ret;
455 }497 }
456 498
457 kref_init(&exec->refcount);499 if (args->bcl_start != args->bcl_end) {
500 bin = kcalloc(1, sizeof(*bin), GFP_KERNEL);
501 if (!bin)
502 return -ENOMEM;
458 503
459 ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,504 ret = v3d_job_init(v3d, file_priv, &bin->base,
460 0, 0, &exec->bin.in_fence);505 v3d_job_free, args->in_sync_bcl);
461 if (ret == -EINVAL)506 if (ret) {
462 goto fail;507 v3d_job_put(&render->base);
508 return ret;
509 }
463 510
464 ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,511 bin->start = args->bcl_start;
465 0, 0, &exec->render.in_fence);512 bin->end = args->bcl_end;
466 if (ret == -EINVAL)513 bin->qma = args->qma;
467 goto fail;514 bin->qms = args->qms;
515 bin->qts = args->qts;
516 bin->render = render;
517 }
468 518
469 exec->qma = args->qma;519 ret = v3d_lookup_bos(dev, file_priv, &render->base,
470 exec->qms = args->qms;520 args->bo_handles, args->bo_handle_count);
471 exec->qts = args->qts;
472 exec->bin.exec = exec;
473 exec->bin.start = args->bcl_start;
474 exec->bin.end = args->bcl_end;
475 exec->render.exec = exec;
476 exec->render.start = args->rcl_start;
477 exec->render.end = args->rcl_end;
478 exec->v3d = v3d;
479 INIT_LIST_HEAD(&exec->unref_list);
480
481 ret = v3d_cl_lookup_bos(dev, file_priv, args, exec);
482 if (ret)521 if (ret)
483 goto fail;522 goto fail;
484 523
485 ret = v3d_lock_bo_reservations(exec->bo, exec->bo_count,524 ret = v3d_lock_bo_reservations(render->base.bo, render->base.bo_count,
486 &acquire_ctx);525 &acquire_ctx);
487 if (ret)526 if (ret)
488 goto fail;527 goto fail;
489 528
490 mutex_lock(&v3d->sched_lock);529 mutex_lock(&v3d->sched_lock);
491 if (exec->bin.start != exec->bin.end) {530 if (bin) {
492 ret = drm_sched_job_init(&exec->bin.base,531 ret = v3d_push_job(v3d_priv, &bin->base, V3D_BIN);
493 &v3d_priv->sched_entity[V3D_BIN],
494 v3d_priv);
495 if (ret)532 if (ret)
496 goto fail_unreserve;533 goto fail_unreserve;
497 534
498 exec->bin_done_fence =535 render->bin_done_fence = dma_fence_get(bin->base.done_fence);
499 dma_fence_get(&exec->bin.base.s_fence->finished);
500
501 kref_get(&exec->refcount); /* put by scheduler job completion */
502 drm_sched_entity_push_job(&exec->bin.base,
503 &v3d_priv->sched_entity[V3D_BIN]);
504 }536 }
505 537
506 ret = drm_sched_job_init(&exec->render.base,538 ret = v3d_push_job(v3d_priv, &render->base, V3D_RENDER);
507 &v3d_priv->sched_entity[V3D_RENDER],
508 v3d_priv);
509 if (ret)539 if (ret)
510 goto fail_unreserve;540 goto fail_unreserve;
511
512 exec->render_done_fence =
513 dma_fence_get(&exec->render.base.s_fence->finished);
514
515 kref_get(&exec->refcount); /* put by scheduler job completion */
516 drm_sched_entity_push_job(&exec->render.base,
517 &v3d_priv->sched_entity[V3D_RENDER]);
518 mutex_unlock(&v3d->sched_lock);541 mutex_unlock(&v3d->sched_lock);
519 542
520 v3d_attach_object_fences(exec->bo, exec->bo_count,543 v3d_attach_fences_and_unlock_reservation(file_priv,
521 exec->render_done_fence);544 &render->base, &acquire_ctx,
522 545 args->out_sync);
523 drm_gem_unlock_reservations(exec->bo, exec->bo_count, &acquire_ctx);
524
525 /* Update the return sync object for the */
526 sync_out = drm_syncobj_find(file_priv, args->out_sync);
527 if (sync_out) {
528 drm_syncobj_replace_fence(sync_out, exec->render_done_fence);
529 drm_syncobj_put(sync_out);
530 }
531 546
532 v3d_exec_put(exec);547 if (bin)
548 v3d_job_put(&bin->base);
549 v3d_job_put(&render->base);
533 550
534 return 0;551 return 0;
535 552
536fail_unreserve:553fail_unreserve:
537 mutex_unlock(&v3d->sched_lock);554 mutex_unlock(&v3d->sched_lock);
538 drm_gem_unlock_reservations(exec->bo, exec->bo_count, &acquire_ctx);555 drm_gem_unlock_reservations(render->base.bo,
556 render->base.bo_count, &acquire_ctx);
539fail:557fail:
540 v3d_exec_put(exec);558 if (bin)
559 v3d_job_put(&bin->base);
560 v3d_job_put(&render->base);
541 561
542 return ret;562 return ret;
543}563}
@@ -560,10 +580,7 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, · 16 unmodified lines
560 struct drm_v3d_submit_tfu *args = data;580 struct drm_v3d_submit_tfu *args = data;
561 struct v3d_tfu_job *job;581 struct v3d_tfu_job *job;
562 struct ww_acquire_ctx acquire_ctx;582 struct ww_acquire_ctx acquire_ctx;
563 struct drm_syncobj *sync_out;
564 struct dma_fence *sched_done_fence;
565 int ret = 0;583 int ret = 0;
566 int bo_count;
567 584
568 trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);585 trace_v3d_submit_tfu_ioctl(&v3d->drm, args->iia);
569 586
@@ -571,81 +588,71 @@ v3d_submit_tfu_ioctl(struct drm_device *dev, void *data, · 1 unmodified line
571 if (!job)588 if (!job)
572 return -ENOMEM;589 return -ENOMEM;
573 590
574 ret = pm_runtime_get_sync(v3d->dev);591 ret = v3d_job_init(v3d, file_priv, &job->base,
575 if (ret < 0) {592 v3d_job_free, args->in_sync);
593 if (ret) {
576 kfree(job);594 kfree(job);
577 return ret;595 return ret;
578 }596 }
579 597
580 kref_init(&job->refcount);598 job->base.bo = kcalloc(ARRAY_SIZE(args->bo_handles),
581 599 sizeof(*job->base.bo), GFP_KERNEL);
582 ret = drm_syncobj_find_fence(file_priv, args->in_sync,600 if (!job->base.bo) {
583 0, 0, &job->in_fence);601 v3d_job_put(&job->base);
584 if (ret == -EINVAL)602 return -ENOMEM;
585 goto fail;603 }
586 604
587 job->args = *args;605 job->args = *args;
588 job->v3d = v3d;
589 606
590 spin_lock(&file_priv->table_lock);607 spin_lock(&file_priv->table_lock);
591 for (bo_count = 0; bo_count < ARRAY_SIZE(job->bo); bo_count++) {608 for (job->base.bo_count = 0;
609 job->base.bo_count < ARRAY_SIZE(args->bo_handles);
610 job->base.bo_count++) {
592 struct drm_gem_object *bo;611 struct drm_gem_object *bo;
593 612
594 if (!args->bo_handles[bo_count])613 if (!args->bo_handles[job->base.bo_count])
595 break;614 break;
596 615
597 bo = idr_find(&file_priv->object_idr,616 bo = idr_find(&file_priv->object_idr,
598 args->bo_handles[bo_count]);617 args->bo_handles[job->base.bo_count]);
599 if (!bo) {618 if (!bo) {
600 DRM_DEBUG("Failed to look up GEM BO %d: %d\n",619 DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
601 bo_count, args->bo_handles[bo_count]);620 job->base.bo_count,
621 args->bo_handles[job->base.bo_count]);
602 ret = -ENOENT;622 ret = -ENOENT;
603 spin_unlock(&file_priv->table_lock);623 spin_unlock(&file_priv->table_lock);
604 goto fail;624 goto fail;
605 }625 }
606 drm_gem_object_get(bo);626 drm_gem_object_get(bo);
607 job->bo[bo_count] = bo;627 job->base.bo[job->base.bo_count] = bo;
608 }628 }
609 spin_unlock(&file_priv->table_lock);629 spin_unlock(&file_priv->table_lock);
610 630
611 ret = v3d_lock_bo_reservations(job->bo, bo_count, &acquire_ctx);631 ret = v3d_lock_bo_reservations(job->base.bo, job->base.bo_count,
632 &acquire_ctx);
612 if (ret)633 if (ret)
613 goto fail;634 goto fail;
614 635
615 mutex_lock(&v3d->sched_lock);636 mutex_lock(&v3d->sched_lock);
616 ret = drm_sched_job_init(&job->base,637 ret = v3d_push_job(v3d_priv, &job->base, V3D_TFU);
617 &v3d_priv->sched_entity[V3D_TFU],
618 v3d_priv);
619 if (ret)638 if (ret)
620 goto fail_unreserve;639 goto fail_unreserve;
621
622 sched_done_fence = dma_fence_get(&job->base.s_fence->finished);
623
624 kref_get(&job->refcount); /* put by scheduler job completion */
625 drm_sched_entity_push_job(&job->base, &v3d_priv->sched_entity[V3D_TFU]);
626 mutex_unlock(&v3d->sched_lock);640 mutex_unlock(&v3d->sched_lock);
627 641
628 v3d_attach_object_fences(job->bo, bo_count, sched_done_fence);642 v3d_attach_fences_and_unlock_reservation(file_priv,
629 643 &job->base, &acquire_ctx,
630 drm_gem_unlock_reservations(job->bo, bo_count, &acquire_ctx);644 args->out_sync);
631
632 /* Update the return sync object */
633 sync_out = drm_syncobj_find(file_priv, args->out_sync);
634 if (sync_out) {
635 drm_syncobj_replace_fence(sync_out, sched_done_fence);
636 drm_syncobj_put(sync_out);
637 }
638 dma_fence_put(sched_done_fence);
639 645
640 v3d_tfu_job_put(job);646 v3d_job_put(&job->base);
641 647
642 return 0;648 return 0;
643 649
644fail_unreserve:650fail_unreserve:
645 mutex_unlock(&v3d->sched_lock);651 mutex_unlock(&v3d->sched_lock);
646 drm_gem_unlock_reservations(job->bo, bo_count, &acquire_ctx);652 drm_gem_unlock_reservations(job->base.bo, job->base.bo_count,
653 &acquire_ctx);
647fail:654fail:
648 v3d_tfu_job_put(job);655 v3d_job_put(&job->base);
649 656
650 return ret;657 return ret;
651}658}
@@ -703,7 +710,7 @@ v3d_gem_destroy(struct drm_device *dev) · 51 unmodified lines
703 710
704 v3d_sched_fini(v3d);711 v3d_sched_fini(v3d);
705 712
706 /* Waiting for exec to finish would need to be done before713 /* Waiting for jobs to finish would need to be done before
707 * unregistering V3D.714 * unregistering V3D.
708 */715 */
709 WARN_ON(v3d->bin_job);716 WARN_ON(v3d->bin_job);
drivers/gpu/drm/v3d/v3d_irq.c+4−4
@@ -62,7 +62,7 @@ v3d_overflow_mem_work(struct work_struct *work) · 61 unmodified lines
62 }62 }
63 63
64 drm_gem_object_get(obj);64 drm_gem_object_get(obj);
65 list_add_tail(&bo->unref_head, &v3d->bin_job->unref_list);65 list_add_tail(&bo->unref_head, &v3d->bin_job->render->unref_list);
66 spin_unlock_irqrestore(&v3d->job_lock, irqflags);66 spin_unlock_irqrestore(&v3d->job_lock, irqflags);
67 67
68 V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT);68 V3D_CORE_WRITE(0, V3D_PTB_BPOA, bo->node.start << PAGE_SHIFT);
@@ -96,7 +96,7 @@ v3d_irq(int irq, void *arg) · 27 unmodified lines
96 96
97 if (intsts & V3D_INT_FLDONE) {97 if (intsts & V3D_INT_FLDONE) {
98 struct v3d_fence *fence =98 struct v3d_fence *fence =
99 to_v3d_fence(v3d->bin_job->bin.irq_fence);99 to_v3d_fence(v3d->bin_job->base.irq_fence);
100 100
101 trace_v3d_bcl_irq(&v3d->drm, fence->seqno);101 trace_v3d_bcl_irq(&v3d->drm, fence->seqno);
102 dma_fence_signal(&fence->base);102 dma_fence_signal(&fence->base);
@@ -105,7 +105,7 @@ v3d_irq(int irq, void *arg) · 2 unmodified lines
105 105
106 if (intsts & V3D_INT_FRDONE) {106 if (intsts & V3D_INT_FRDONE) {
107 struct v3d_fence *fence =107 struct v3d_fence *fence =
108 to_v3d_fence(v3d->render_job->render.irq_fence);108 to_v3d_fence(v3d->render_job->base.irq_fence);
109 109
110 trace_v3d_rcl_irq(&v3d->drm, fence->seqno);110 trace_v3d_rcl_irq(&v3d->drm, fence->seqno);
111 dma_fence_signal(&fence->base);111 dma_fence_signal(&fence->base);
@@ -141,7 +141,7 @@ v3d_hub_irq(int irq, void *arg) · 29 unmodified lines
141 141
142 if (intsts & V3D_HUB_INT_TFUC) {142 if (intsts & V3D_HUB_INT_TFUC) {
143 struct v3d_fence *fence =143 struct v3d_fence *fence =
144 to_v3d_fence(v3d->tfu_job->irq_fence);144 to_v3d_fence(v3d->tfu_job->base.irq_fence);
145 145
146 trace_v3d_tfu_irq(&v3d->drm, fence->seqno);146 trace_v3d_tfu_irq(&v3d->drm, fence->seqno);
147 dma_fence_signal(&fence->base);147 dma_fence_signal(&fence->base);
drivers/gpu/drm/v3d/v3d_sched.c+151−108
@@ -30,43 +30,44 @@ to_v3d_job(struct drm_sched_job *sched_job) · 29 unmodified lines
30 return container_of(sched_job, struct v3d_job, base);30 return container_of(sched_job, struct v3d_job, base);
31}31}
32 32
33static struct v3d_tfu_job *33static struct v3d_bin_job *
34to_tfu_job(struct drm_sched_job *sched_job)34to_bin_job(struct drm_sched_job *sched_job)
35{35{
36 return container_of(sched_job, struct v3d_tfu_job, base);36 return container_of(sched_job, struct v3d_bin_job, base.base);
37}37}
38 38
39static void39static struct v3d_render_job *
40v3d_job_free(struct drm_sched_job *sched_job)40to_render_job(struct drm_sched_job *sched_job)
41{41{
42 struct v3d_job *job = to_v3d_job(sched_job);42 return container_of(sched_job, struct v3d_render_job, base.base);
43 43}
44 drm_sched_job_cleanup(sched_job);
45 44
46 v3d_exec_put(job->exec);45static struct v3d_tfu_job *
46to_tfu_job(struct drm_sched_job *sched_job)
47{
48 return container_of(sched_job, struct v3d_tfu_job, base.base);
47}49}
48 50
49static void51static void
50v3d_tfu_job_free(struct drm_sched_job *sched_job)52v3d_job_free(struct drm_sched_job *sched_job)
51{53{
52 struct v3d_tfu_job *job = to_tfu_job(sched_job);54 struct v3d_job *job = to_v3d_job(sched_job);
53 55
54 drm_sched_job_cleanup(sched_job);56 drm_sched_job_cleanup(sched_job);
55 57 v3d_job_put(job);
56 v3d_tfu_job_put(job);
57}58}
58 59
59/**60/**
60 * Returns the fences that the bin or render job depends on, one by one.61 * Returns the fences that the job depends on, one by one.
61 * v3d_job_run() won't be called until all of them have been signaled.62 *
63 * If placed in the scheduler's .dependency method, the corresponding
64 * .run_job won't be called until all of them have been signaled.
62 */65 */
63static struct dma_fence *66static struct dma_fence *
64v3d_job_dependency(struct drm_sched_job *sched_job,67v3d_job_dependency(struct drm_sched_job *sched_job,
65 struct drm_sched_entity *s_entity)68 struct drm_sched_entity *s_entity)
66{69{
67 struct v3d_job *job = to_v3d_job(sched_job);70 struct v3d_job *job = to_v3d_job(sched_job);
68 struct v3d_exec_info *exec = job->exec;
69 enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
70 struct dma_fence *fence;71 struct dma_fence *fence;
71 72
72 fence = job->in_fence;73 fence = job->in_fence;
@@ -75,113 +76,132 @@ v3d_job_dependency(struct drm_sched_job *sched_job, · 2 unmodified lines
75 return fence;76 return fence;
76 }77 }
77 78
78 if (q == V3D_RENDER) {
79 /* If we had a bin job, the render job definitely depends on
80 * it. We first have to wait for bin to be scheduled, so that
81 * its done_fence is created.
82 */
83 fence = exec->bin_done_fence;
84 if (fence) {
85 exec->bin_done_fence = NULL;
86 return fence;
87 }
88 }
89
90 /* XXX: Wait on a fence for switching the GMP if necessary,79 /* XXX: Wait on a fence for switching the GMP if necessary,
91 * and then do so.80 * and then do so.
92 */81 */
93 82
94 return fence;83 return NULL;
95}84}
96 85
97/**86/**
98 * Returns the fences that the TFU job depends on, one by one.87 * Returns the fences that the render job depends on, one by one.
99 * v3d_tfu_job_run() won't be called until all of them have been88 * v3d_job_run() won't be called until all of them have been signaled.
100 * signaled.
101 */89 */
102static struct dma_fence *90static struct dma_fence *
103v3d_tfu_job_dependency(struct drm_sched_job *sched_job,91v3d_render_job_dependency(struct drm_sched_job *sched_job,
104 struct drm_sched_entity *s_entity)92 struct drm_sched_entity *s_entity)
105{93{
106 struct v3d_tfu_job *job = to_tfu_job(sched_job);94 struct v3d_render_job *job = to_render_job(sched_job);
107 struct dma_fence *fence;95 struct dma_fence *fence;
108 96
109 fence = job->in_fence;97 fence = v3d_job_dependency(sched_job, s_entity);
98 if (fence)
99 return fence;
100
101 /* If we had a bin job, the render job definitely depends on
102 * it. We first have to wait for bin to be scheduled, so that
103 * its done_fence is created.
104 */
105 fence = job->bin_done_fence;
110 if (fence) {106 if (fence) {
111 job->in_fence = NULL;107 job->bin_done_fence = NULL;
112 return fence;108 return fence;
113 }109 }
114 110
115 return NULL;111 return fence;
116}112}
117 113
118static struct dma_fence *v3d_job_run(struct drm_sched_job *sched_job)114static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
119{115{
120 struct v3d_job *job = to_v3d_job(sched_job);116 struct v3d_bin_job *job = to_bin_job(sched_job);
121 struct v3d_exec_info *exec = job->exec;117 struct v3d_dev *v3d = job->base.v3d;
122 enum v3d_queue q = job == &exec->bin ? V3D_BIN : V3D_RENDER;
123 struct v3d_dev *v3d = exec->v3d;
124 struct drm_device *dev = &v3d->drm;118 struct drm_device *dev = &v3d->drm;
125 struct dma_fence *fence;119 struct dma_fence *fence;
126 unsigned long irqflags;120 unsigned long irqflags;
127 121
128 if (unlikely(job->base.s_fence->finished.error))122 if (unlikely(job->base.base.s_fence->finished.error))
129 return NULL;123 return NULL;
130 124
131 /* Lock required around bin_job update vs125 /* Lock required around bin_job update vs
132 * v3d_overflow_mem_work().126 * v3d_overflow_mem_work().
133 */127 */
134 spin_lock_irqsave(&v3d->job_lock, irqflags);128 spin_lock_irqsave(&v3d->job_lock, irqflags);
135 if (q == V3D_BIN) {129 v3d->bin_job = job;
136 v3d->bin_job = job->exec;130 /* Clear out the overflow allocation, so we don't
137 131 * reuse the overflow attached to a previous job.
138 /* Clear out the overflow allocation, so we don't132 */
139 * reuse the overflow attached to a previous job.133 V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
140 */
141 V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
142 } else {
143 v3d->render_job = job->exec;
144 }
145 spin_unlock_irqrestore(&v3d->job_lock, irqflags);134 spin_unlock_irqrestore(&v3d->job_lock, irqflags);
146 135
147 /* Can we avoid this flush when q==RENDER? We need to be136 v3d_invalidate_caches(v3d);
148 * careful of scheduling, though -- imagine job0 rendering to137
149 * texture and job1 reading, and them being executed as bin0,138 fence = v3d_fence_create(v3d, V3D_BIN);
150 * bin1, render0, render1, so that render1's flush at bin time139 if (IS_ERR(fence))
140 return NULL;
141
142 if (job->base.irq_fence)
143 dma_fence_put(job->base.irq_fence);
144 job->base.irq_fence = dma_fence_get(fence);
145
146 trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno,
147 job->start, job->end);
148
149 /* Set the current and end address of the control list.
150 * Writing the end register is what starts the job.
151 */
152 if (job->qma) {
153 V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, job->qma);
154 V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, job->qms);
155 }
156 if (job->qts) {
157 V3D_CORE_WRITE(0, V3D_CLE_CT0QTS,
158 V3D_CLE_CT0QTS_ENABLE |
159 job->qts);
160 }
161 V3D_CORE_WRITE(0, V3D_CLE_CT0QBA, job->start);
162 V3D_CORE_WRITE(0, V3D_CLE_CT0QEA, job->end);
163
164 return fence;
165}
166
167static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
168{
169 struct v3d_render_job *job = to_render_job(sched_job);
170 struct v3d_dev *v3d = job->base.v3d;
171 struct drm_device *dev = &v3d->drm;
172 struct dma_fence *fence;
173
174 if (unlikely(job->base.base.s_fence->finished.error))
175 return NULL;
176
177 v3d->render_job = job;
178
179 /* Can we avoid this flush? We need to be careful of
180 * scheduling, though -- imagine job0 rendering to texture and
181 * job1 reading, and them being executed as bin0, bin1,
182 * render0, render1, so that render1's flush at bin time
151 * wasn't enough.183 * wasn't enough.
152 */184 */
153 v3d_invalidate_caches(v3d);185 v3d_invalidate_caches(v3d);
154 186
155 fence = v3d_fence_create(v3d, q);187 fence = v3d_fence_create(v3d, V3D_RENDER);
156 if (IS_ERR(fence))188 if (IS_ERR(fence))
157 return NULL;189 return NULL;
158 190
159 if (job->irq_fence)191 if (job->base.irq_fence)
160 dma_fence_put(job->irq_fence);192 dma_fence_put(job->base.irq_fence);
161 job->irq_fence = dma_fence_get(fence);193 job->base.irq_fence = dma_fence_get(fence);
162 194
163 trace_v3d_submit_cl(dev, q == V3D_RENDER, to_v3d_fence(fence)->seqno,195 trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno,
164 job->start, job->end);196 job->start, job->end);
165 197
166 if (q == V3D_BIN) {198 /* XXX: Set the QCFG */
167 if (exec->qma) {
168 V3D_CORE_WRITE(0, V3D_CLE_CT0QMA, exec->qma);
169 V3D_CORE_WRITE(0, V3D_CLE_CT0QMS, exec->qms);
170 }
171 if (exec->qts) {
172 V3D_CORE_WRITE(0, V3D_CLE_CT0QTS,
173 V3D_CLE_CT0QTS_ENABLE |
174 exec->qts);
175 }
176 } else {
177 /* XXX: Set the QCFG */
178 }
179 199
180 /* Set the current and end address of the control list.200 /* Set the current and end address of the control list.
181 * Writing the end register is what starts the job.201 * Writing the end register is what starts the job.
182 */202 */
183 V3D_CORE_WRITE(0, V3D_CLE_CTNQBA(q), job->start);203 V3D_CORE_WRITE(0, V3D_CLE_CT1QBA, job->start);
184 V3D_CORE_WRITE(0, V3D_CLE_CTNQEA(q), job->end);204 V3D_CORE_WRITE(0, V3D_CLE_CT1QEA, job->end);
185 205
186 return fence;206 return fence;
187}207}
@@ -190,7 +210,7 @@ static struct dma_fence * · 2 unmodified lines
190v3d_tfu_job_run(struct drm_sched_job *sched_job)210v3d_tfu_job_run(struct drm_sched_job *sched_job)
191{211{
192 struct v3d_tfu_job *job = to_tfu_job(sched_job);212 struct v3d_tfu_job *job = to_tfu_job(sched_job);
193 struct v3d_dev *v3d = job->v3d;213 struct v3d_dev *v3d = job->base.v3d;
194 struct drm_device *dev = &v3d->drm;214 struct drm_device *dev = &v3d->drm;
195 struct dma_fence *fence;215 struct dma_fence *fence;
196 216
@@ -199,9 +219,9 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job) · 2 unmodified lines
199 return NULL;219 return NULL;
200 220
201 v3d->tfu_job = job;221 v3d->tfu_job = job;
202 if (job->irq_fence)222 if (job->base.irq_fence)
203 dma_fence_put(job->irq_fence);223 dma_fence_put(job->base.irq_fence);
204 job->irq_fence = dma_fence_get(fence);224 job->base.irq_fence = dma_fence_get(fence);
205 225
206 trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);226 trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
207 227
@@ -251,51 +271,74 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job) · 43 unmodified lines
251 mutex_unlock(&v3d->reset_lock);271 mutex_unlock(&v3d->reset_lock);
252}272}
253 273
274/* If the current address or return address have changed, then the GPU
275 * has probably made progress and we should delay the reset. This
276 * could fail if the GPU got in an infinite loop in the CL, but that
277 * is pretty unlikely outside of an i-g-t testcase.
278 */
254static void279static void
255v3d_job_timedout(struct drm_sched_job *sched_job)280v3d_cl_job_timedout(struct drm_sched_job *sched_job, enum v3d_queue q,
281 u32 *timedout_ctca, u32 *timedout_ctra)
256{282{
257 struct v3d_job *job = to_v3d_job(sched_job);283 struct v3d_job *job = to_v3d_job(sched_job);
258 struct v3d_exec_info *exec = job->exec;284 struct v3d_dev *v3d = job->v3d;
259 struct v3d_dev *v3d = exec->v3d;285 u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(q));
260 enum v3d_queue job_q = job == &exec->bin ? V3D_BIN : V3D_RENDER;286 u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(q));
261 u32 ctca = V3D_CORE_READ(0, V3D_CLE_CTNCA(job_q));287
262 u32 ctra = V3D_CORE_READ(0, V3D_CLE_CTNRA(job_q));288 if (*timedout_ctca != ctca || *timedout_ctra != ctra) {
263 289 *timedout_ctca = ctca;
264 /* If the current address or return address have changed, then290 *timedout_ctra = ctra;
265 * the GPU has probably made progress and we should delay the
266 * reset. This could fail if the GPU got in an infinite loop
267 * in the CL, but that is pretty unlikely outside of an i-g-t
268 * testcase.
269 */
270 if (job->timedout_ctca != ctca || job->timedout_ctra != ctra) {
271 job->timedout_ctca = ctca;
272 job->timedout_ctra = ctra;
273 return;291 return;
274 }292 }
275 293
276 v3d_gpu_reset_for_timeout(v3d, sched_job);294 v3d_gpu_reset_for_timeout(v3d, sched_job);
277}295}
278 296
297static void
298v3d_bin_job_timedout(struct drm_sched_job *sched_job)
299{
300 struct v3d_bin_job *job = to_bin_job(sched_job);
301
302 v3d_cl_job_timedout(sched_job, V3D_BIN,
303 &job->timedout_ctca, &job->timedout_ctra);
304}
305
306static void
307v3d_render_job_timedout(struct drm_sched_job *sched_job)
308{
309 struct v3d_render_job *job = to_render_job(sched_job);
310
311 v3d_cl_job_timedout(sched_job, V3D_RENDER,
312 &job->timedout_ctca, &job->timedout_ctra);
313}
314
279static void315static void
280v3d_tfu_job_timedout(struct drm_sched_job *sched_job)316v3d_tfu_job_timedout(struct drm_sched_job *sched_job)
281{317{
282 struct v3d_tfu_job *job = to_tfu_job(sched_job);318 struct v3d_job *job = to_v3d_job(sched_job);
283 319
284 v3d_gpu_reset_for_timeout(job->v3d, sched_job);320 v3d_gpu_reset_for_timeout(job->v3d, sched_job);
285}321}
286 322
287static const struct drm_sched_backend_ops v3d_sched_ops = {323static const struct drm_sched_backend_ops v3d_bin_sched_ops = {
288 .dependency = v3d_job_dependency,324 .dependency = v3d_job_dependency,
289 .run_job = v3d_job_run,325 .run_job = v3d_bin_job_run,
290 .timedout_job = v3d_job_timedout,326 .timedout_job = v3d_bin_job_timedout,
291 .free_job = v3d_job_free327 .free_job = v3d_job_free,
328};
329
330static const struct drm_sched_backend_ops v3d_render_sched_ops = {
331 .dependency = v3d_render_job_dependency,
332 .run_job = v3d_render_job_run,
333 .timedout_job = v3d_render_job_timedout,
334 .free_job = v3d_job_free,
292};335};
293 336
294static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {337static const struct drm_sched_backend_ops v3d_tfu_sched_ops = {
295 .dependency = v3d_tfu_job_dependency,338 .dependency = v3d_job_dependency,
296 .run_job = v3d_tfu_job_run,339 .run_job = v3d_tfu_job_run,
297 .timedout_job = v3d_tfu_job_timedout,340 .timedout_job = v3d_tfu_job_timedout,
298 .free_job = v3d_tfu_job_free341 .free_job = v3d_job_free,
299};342};
300 343
301int344int
@@ -307,7 +350,7 @@ v3d_sched_init(struct v3d_dev *v3d) · 5 unmodified lines
307 int ret;350 int ret;
308 351
309 ret = drm_sched_init(&v3d->queue[V3D_BIN].sched,352 ret = drm_sched_init(&v3d->queue[V3D_BIN].sched,
310 &v3d_sched_ops,353 &v3d_bin_sched_ops,
311 hw_jobs_limit, job_hang_limit,354 hw_jobs_limit, job_hang_limit,
312 msecs_to_jiffies(hang_limit_ms),355 msecs_to_jiffies(hang_limit_ms),
313 "v3d_bin");356 "v3d_bin");
@@ -317,7 +360,7 @@ v3d_sched_init(struct v3d_dev *v3d) · 3 unmodified lines
317 }360 }
318 361
319 ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,362 ret = drm_sched_init(&v3d->queue[V3D_RENDER].sched,
320 &v3d_sched_ops,363 &v3d_render_sched_ops,
321 hw_jobs_limit, job_hang_limit,364 hw_jobs_limit, job_hang_limit,
322 msecs_to_jiffies(hang_limit_ms),365 msecs_to_jiffies(hang_limit_ms),
323 "v3d_render");366 "v3d_render");