Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/panfrost: Queue jobs on the hardware

The hardware has a set of '_NEXT' registers that can hold a second job
while the first is executing. Make use of these registers to enqueue a
second job per slot.

v5:
* Fix a comment in panfrost_job_init()

v3:
* Fix the done/err job dequeuing logic to get a valid active state
* Only enable the second slot on GPUs supporting jobchain disambiguation
* Split interrupt handling in sub-functions

Signed-off-by: Steven Price <steven.price@arm.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210630062751.2832545-16-boris.brezillon@collabora.com

authored by

Steven Price and committed by
Boris Brezillon
030761e0 30b5d4ed

+351 -118
+1 -1
drivers/gpu/drm/panfrost/panfrost_device.h
··· 102 102 103 103 struct panfrost_job_slot *js; 104 104 105 - struct panfrost_job *jobs[NUM_JOB_SLOTS]; 105 + struct panfrost_job *jobs[NUM_JOB_SLOTS][2]; 106 106 struct list_head scheduled_jobs; 107 107 108 108 struct panfrost_perfcnt *perfcnt;
+350 -117
drivers/gpu/drm/panfrost/panfrost_job.c
··· 4 4 #include <linux/delay.h> 5 5 #include <linux/interrupt.h> 6 6 #include <linux/io.h> 7 + #include <linux/iopoll.h> 7 8 #include <linux/platform_device.h> 8 9 #include <linux/pm_runtime.h> 9 10 #include <linux/dma-resv.h> ··· 141 140 job_write(pfdev, JS_AFFINITY_NEXT_HI(js), affinity >> 32); 142 141 } 143 142 143 + static u32 144 + panfrost_get_job_chain_flag(const struct panfrost_job *job) 145 + { 146 + struct panfrost_fence *f = to_panfrost_fence(job->done_fence); 147 + 148 + if (!panfrost_has_hw_feature(job->pfdev, HW_FEATURE_JOBCHAIN_DISAMBIGUATION)) 149 + return 0; 150 + 151 + return (f->seqno & 1) ? JS_CONFIG_JOB_CHAIN_FLAG : 0; 152 + } 153 + 154 + static struct panfrost_job * 155 + panfrost_dequeue_job(struct panfrost_device *pfdev, int slot) 156 + { 157 + struct panfrost_job *job = pfdev->jobs[slot][0]; 158 + 159 + WARN_ON(!job); 160 + pfdev->jobs[slot][0] = pfdev->jobs[slot][1]; 161 + pfdev->jobs[slot][1] = NULL; 162 + 163 + return job; 164 + } 165 + 166 + static unsigned int 167 + panfrost_enqueue_job(struct panfrost_device *pfdev, int slot, 168 + struct panfrost_job *job) 169 + { 170 + if (WARN_ON(!job)) 171 + return 0; 172 + 173 + if (!pfdev->jobs[slot][0]) { 174 + pfdev->jobs[slot][0] = job; 175 + return 0; 176 + } 177 + 178 + WARN_ON(pfdev->jobs[slot][1]); 179 + pfdev->jobs[slot][1] = job; 180 + WARN_ON(panfrost_get_job_chain_flag(job) == 181 + panfrost_get_job_chain_flag(pfdev->jobs[slot][0])); 182 + return 1; 183 + } 184 + 144 185 static void panfrost_job_hw_submit(struct panfrost_job *job, int js) 145 186 { 146 187 struct panfrost_device *pfdev = job->pfdev; 188 + unsigned int subslot; 147 189 u32 cfg; 148 190 u64 jc_head = job->jc; 149 191 int ret; ··· 212 168 * start */ 213 169 cfg |= JS_CONFIG_THREAD_PRI(8) | 214 170 JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE | 215 - JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE; 171 + JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE | 172 + panfrost_get_job_chain_flag(job); 216 173 217 174 if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) 218 175 cfg |= JS_CONFIG_ENABLE_FLUSH_REDUCTION; ··· 227 182 job_write(pfdev, JS_FLUSH_ID_NEXT(js), job->flush_id); 228 183 229 184 /* GO ! */ 230 - dev_dbg(pfdev->dev, "JS: Submitting atom %p to js[%d] with head=0x%llx", 231 - job, js, jc_head); 232 185 233 - job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START); 186 + spin_lock(&pfdev->js->job_lock); 187 + subslot = panfrost_enqueue_job(pfdev, js, job); 188 + /* Don't queue the job if a reset is in progress */ 189 + if (!atomic_read(&pfdev->reset.pending)) { 190 + job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START); 191 + dev_dbg(pfdev->dev, 192 + "JS: Submitting atom %p to js[%d][%d] with head=0x%llx AS %d", 193 + job, js, subslot, jc_head, cfg & 0xf); 194 + } 195 + spin_unlock(&pfdev->js->job_lock); 234 196 } 235 197 236 198 static int panfrost_acquire_object_fences(struct drm_gem_object **bos, ··· 384 332 if (unlikely(job->base.s_fence->finished.error)) 385 333 return NULL; 386 334 387 - pfdev->jobs[slot] = job; 335 + /* Nothing to execute: can happen if the job has finished while 336 + * we were resetting the GPU. 337 + */ 338 + if (!job->jc) 339 + return NULL; 388 340 389 341 fence = panfrost_fence_create(pfdev, slot); 390 342 if (IS_ERR(fence)) ··· 416 360 job_write(pfdev, JOB_INT_MASK, irq_mask); 417 361 } 418 362 419 - static void panfrost_reset(struct panfrost_device *pfdev, 420 - struct drm_sched_job *bad) 363 + static void panfrost_job_handle_err(struct panfrost_device *pfdev, 364 + struct panfrost_job *job, 365 + unsigned int js) 421 366 { 422 - unsigned int i; 367 + u32 js_status = job_read(pfdev, JS_STATUS(js)); 368 + const char *exception_name = panfrost_exception_name(js_status); 369 + bool signal_fence = true; 370 + 371 + if (!panfrost_exception_is_fault(js_status)) { 372 + dev_dbg(pfdev->dev, "js event, js=%d, status=%s, head=0x%x, tail=0x%x", 373 + js, exception_name, 374 + job_read(pfdev, JS_HEAD_LO(js)), 375 + job_read(pfdev, JS_TAIL_LO(js))); 376 + } else { 377 + dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x", 378 + js, exception_name, 379 + job_read(pfdev, JS_HEAD_LO(js)), 380 + job_read(pfdev, JS_TAIL_LO(js))); 381 + } 382 + 383 + if (js_status == DRM_PANFROST_EXCEPTION_STOPPED) { 384 + /* Update the job head so we can resume */ 385 + job->jc = job_read(pfdev, JS_TAIL_LO(js)) | 386 + ((u64)job_read(pfdev, JS_TAIL_HI(js)) << 32); 387 + 388 + /* The job will be resumed, don't signal the fence */ 389 + signal_fence = false; 390 + } else if (js_status == DRM_PANFROST_EXCEPTION_TERMINATED) { 391 + /* Job has been hard-stopped, flag it as canceled */ 392 + dma_fence_set_error(job->done_fence, -ECANCELED); 393 + job->jc = 0; 394 + } else if (panfrost_exception_is_fault(js_status)) { 395 + /* We might want to provide finer-grained error code based on 396 + * the exception type, but unconditionally setting to EINVAL 397 + * is good enough for now. 398 + */ 399 + dma_fence_set_error(job->done_fence, -EINVAL); 400 + job->jc = 0; 401 + } 402 + 403 + panfrost_mmu_as_put(pfdev, job->file_priv->mmu); 404 + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); 405 + 406 + if (signal_fence) 407 + dma_fence_signal_locked(job->done_fence); 408 + 409 + pm_runtime_put_autosuspend(pfdev->dev); 410 + 411 + if (panfrost_exception_needs_reset(pfdev, js_status)) { 412 + atomic_set(&pfdev->reset.pending, 1); 413 + drm_sched_fault(&pfdev->js->queue[js].sched); 414 + } 415 + } 416 + 417 + static void panfrost_job_handle_done(struct panfrost_device *pfdev, 418 + struct panfrost_job *job) 419 + { 420 + /* Set ->jc to 0 to avoid re-submitting an already finished job (can 421 + * happen when we receive the DONE interrupt while doing a GPU reset). 422 + */ 423 + job->jc = 0; 424 + panfrost_mmu_as_put(pfdev, job->file_priv->mmu); 425 + panfrost_devfreq_record_idle(&pfdev->pfdevfreq); 426 + 427 + dma_fence_signal_locked(job->done_fence); 428 + pm_runtime_put_autosuspend(pfdev->dev); 429 + } 430 + 431 + static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status) 432 + { 433 + struct panfrost_job *done[NUM_JOB_SLOTS][2] = {}; 434 + struct panfrost_job *failed[NUM_JOB_SLOTS] = {}; 435 + u32 js_state = 0, js_events = 0; 436 + unsigned int i, j; 437 + 438 + /* First we collect all failed/done jobs. */ 439 + while (status) { 440 + u32 js_state_mask = 0; 441 + 442 + for (j = 0; j < NUM_JOB_SLOTS; j++) { 443 + if (status & MK_JS_MASK(j)) 444 + js_state_mask |= MK_JS_MASK(j); 445 + 446 + if (status & JOB_INT_MASK_DONE(j)) { 447 + if (done[j][0]) 448 + done[j][1] = panfrost_dequeue_job(pfdev, j); 449 + else 450 + done[j][0] = panfrost_dequeue_job(pfdev, j); 451 + } 452 + 453 + if (status & JOB_INT_MASK_ERR(j)) { 454 + /* Cancel the next submission. Will be submitted 455 + * after we're done handling this failure if 456 + * there's no reset pending. 457 + */ 458 + job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_NOP); 459 + failed[j] = panfrost_dequeue_job(pfdev, j); 460 + } 461 + } 462 + 463 + /* JS_STATE is sampled when JOB_INT_CLEAR is written. 464 + * For each BIT(slot) or BIT(slot + 16) bit written to 465 + * JOB_INT_CLEAR, the corresponding bits in JS_STATE 466 + * (BIT(slot) and BIT(slot + 16)) are updated, but this 467 + * is racy. If we only have one job done at the time we 468 + * read JOB_INT_RAWSTAT but the second job fails before we 469 + * clear the status, we end up with a status containing 470 + * only the DONE bit and consider both jobs as DONE since 471 + * JS_STATE reports both NEXT and CURRENT as inactive. 472 + * To prevent that, let's repeat this clear+read steps 473 + * until status is 0. 474 + */ 475 + job_write(pfdev, JOB_INT_CLEAR, status); 476 + js_state &= ~js_state_mask; 477 + js_state |= job_read(pfdev, JOB_INT_JS_STATE) & js_state_mask; 478 + js_events |= status; 479 + status = job_read(pfdev, JOB_INT_RAWSTAT); 480 + } 481 + 482 + /* Then we handle the dequeued jobs. */ 483 + for (j = 0; j < NUM_JOB_SLOTS; j++) { 484 + if (!(js_events & MK_JS_MASK(j))) 485 + continue; 486 + 487 + if (failed[j]) { 488 + panfrost_job_handle_err(pfdev, failed[j], j); 489 + } else if (pfdev->jobs[j][0] && !(js_state & MK_JS_MASK(j))) { 490 + /* When the current job doesn't fail, the JM dequeues 491 + * the next job without waiting for an ACK, this means 492 + * we can have 2 jobs dequeued and only catch the 493 + * interrupt when the second one is done. If both slots 494 + * are inactive, but one job remains in pfdev->jobs[j], 495 + * consider it done. Of course that doesn't apply if a 496 + * failure happened since we cancelled execution of the 497 + * job in _NEXT (see above). 498 + */ 499 + if (WARN_ON(!done[j][0])) 500 + done[j][0] = panfrost_dequeue_job(pfdev, j); 501 + else 502 + done[j][1] = panfrost_dequeue_job(pfdev, j); 503 + } 504 + 505 + for (i = 0; i < ARRAY_SIZE(done[0]) && done[j][i]; i++) 506 + panfrost_job_handle_done(pfdev, done[j][i]); 507 + } 508 + 509 + /* And finally we requeue jobs that were waiting in the second slot 510 + * and have been stopped if we detected a failure on the first slot. 511 + */ 512 + for (j = 0; j < NUM_JOB_SLOTS; j++) { 513 + if (!(js_events & MK_JS_MASK(j))) 514 + continue; 515 + 516 + if (!failed[j] || !pfdev->jobs[j][0]) 517 + continue; 518 + 519 + if (pfdev->jobs[j][0]->jc == 0) { 520 + /* The job was cancelled, signal the fence now */ 521 + struct panfrost_job *canceled = panfrost_dequeue_job(pfdev, j); 522 + 523 + dma_fence_set_error(canceled->done_fence, -ECANCELED); 524 + panfrost_job_handle_done(pfdev, canceled); 525 + } else if (!atomic_read(&pfdev->reset.pending)) { 526 + /* Requeue the job we removed if no reset is pending */ 527 + job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_START); 528 + } 529 + } 530 + } 531 + 532 + static void panfrost_job_handle_irqs(struct panfrost_device *pfdev) 533 + { 534 + u32 status = job_read(pfdev, JOB_INT_RAWSTAT); 535 + 536 + while (status) { 537 + pm_runtime_mark_last_busy(pfdev->dev); 538 + 539 + spin_lock(&pfdev->js->job_lock); 540 + panfrost_job_handle_irq(pfdev, status); 541 + spin_unlock(&pfdev->js->job_lock); 542 + status = job_read(pfdev, JOB_INT_RAWSTAT); 543 + } 544 + } 545 + 546 + static u32 panfrost_active_slots(struct panfrost_device *pfdev, 547 + u32 *js_state_mask, u32 js_state) 548 + { 549 + u32 rawstat; 550 + 551 + if (!(js_state & *js_state_mask)) 552 + return 0; 553 + 554 + rawstat = job_read(pfdev, JOB_INT_RAWSTAT); 555 + if (rawstat) { 556 + unsigned int i; 557 + 558 + for (i = 0; i < NUM_JOB_SLOTS; i++) { 559 + if (rawstat & MK_JS_MASK(i)) 560 + *js_state_mask &= ~MK_JS_MASK(i); 561 + } 562 + } 563 + 564 + return js_state & *js_state_mask; 565 + } 566 + 567 + static void 568 + panfrost_reset(struct panfrost_device *pfdev, 569 + struct drm_sched_job *bad) 570 + { 571 + u32 js_state, js_state_mask = 0xffffffff; 572 + unsigned int i, j; 423 573 bool cookie; 574 + int ret; 424 575 425 576 if (!atomic_read(&pfdev->reset.pending)) 426 577 return; ··· 659 396 job_write(pfdev, JOB_INT_MASK, 0); 660 397 synchronize_irq(pfdev->js->irq); 661 398 662 - /* Schedulers are stopped and interrupts are masked+flushed, we don't 663 - * need to protect the 'evict unfinished jobs' lock with the job_lock. 399 + for (i = 0; i < NUM_JOB_SLOTS; i++) { 400 + /* Cancel the next job and soft-stop the running job. */ 401 + job_write(pfdev, JS_COMMAND_NEXT(i), JS_COMMAND_NOP); 402 + job_write(pfdev, JS_COMMAND(i), JS_COMMAND_SOFT_STOP); 403 + } 404 + 405 + /* Wait at most 10ms for soft-stops to complete */ 406 + ret = readl_poll_timeout(pfdev->iomem + JOB_INT_JS_STATE, js_state, 407 + !panfrost_active_slots(pfdev, &js_state_mask, js_state), 408 + 10, 10000); 409 + 410 + if (ret) 411 + dev_err(pfdev->dev, "Soft-stop failed\n"); 412 + 413 + /* Handle the remaining interrupts before we reset. */ 414 + panfrost_job_handle_irqs(pfdev); 415 + 416 + /* Remaining interrupts have been handled, but we might still have 417 + * stuck jobs. Let's make sure the PM counters stay balanced by 418 + * manually calling pm_runtime_put_noidle() and 419 + * panfrost_devfreq_record_idle() for each stuck job. 664 420 */ 665 421 spin_lock(&pfdev->js->job_lock); 666 422 for (i = 0; i < NUM_JOB_SLOTS; i++) { 667 - if (pfdev->jobs[i]) { 423 + for (j = 0; j < ARRAY_SIZE(pfdev->jobs[0]) && pfdev->jobs[i][j]; j++) { 668 424 pm_runtime_put_noidle(pfdev->dev); 669 425 panfrost_devfreq_record_idle(&pfdev->pfdevfreq); 670 - pfdev->jobs[i] = NULL; 671 426 } 672 427 } 428 + memset(pfdev->jobs, 0, sizeof(pfdev->jobs)); 673 429 spin_unlock(&pfdev->js->job_lock); 674 430 431 + /* Proceed with reset now. */ 675 432 panfrost_device_reset(pfdev); 433 + 434 + /* panfrost_device_reset() unmasks job interrupts, but we want to 435 + * keep them masked a bit longer. 436 + */ 437 + job_write(pfdev, JOB_INT_MASK, 0); 676 438 677 439 /* GPU has been reset, we can clear the reset pending bit. */ 678 440 atomic_set(&pfdev->reset.pending, 0); ··· 714 426 drm_sched_resubmit_jobs(&pfdev->js->queue[i].sched); 715 427 cookie = dma_fence_begin_signalling(); 716 428 429 + /* Restart the schedulers */ 717 430 for (i = 0; i < NUM_JOB_SLOTS; i++) 718 431 drm_sched_start(&pfdev->js->queue[i].sched, true); 432 + 433 + /* Re-enable job interrupts now that everything has been restarted. */ 434 + job_write(pfdev, JOB_INT_MASK, 435 + GENMASK(16 + NUM_JOB_SLOTS - 1, 16) | 436 + GENMASK(NUM_JOB_SLOTS - 1, 0)); 719 437 720 438 dma_fence_end_signalling(cookie); 721 439 } ··· 754 460 return DRM_GPU_SCHED_STAT_NOMINAL; 755 461 } 756 462 463 + static void panfrost_reset_work(struct work_struct *work) 464 + { 465 + struct panfrost_device *pfdev; 466 + 467 + pfdev = container_of(work, struct panfrost_device, reset.work); 468 + panfrost_reset(pfdev, NULL); 469 + } 470 + 757 471 static const struct drm_sched_backend_ops panfrost_sched_ops = { 758 472 .dependency = panfrost_job_dependency, 759 473 .run_job = panfrost_job_run, ··· 769 467 .free_job = panfrost_job_free 770 468 }; 771 469 772 - static void panfrost_job_handle_irq(struct panfrost_device *pfdev, u32 status) 773 - { 774 - int j; 775 - 776 - dev_dbg(pfdev->dev, "jobslot irq status=%x\n", status); 777 - 778 - for (j = 0; status; j++) { 779 - u32 mask = MK_JS_MASK(j); 780 - 781 - if (!(status & mask)) 782 - continue; 783 - 784 - job_write(pfdev, JOB_INT_CLEAR, mask); 785 - 786 - if (status & JOB_INT_MASK_ERR(j)) { 787 - u32 js_status = job_read(pfdev, JS_STATUS(j)); 788 - const char *exception_name = panfrost_exception_name(js_status); 789 - 790 - job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_NOP); 791 - 792 - if (!panfrost_exception_is_fault(js_status)) { 793 - dev_dbg(pfdev->dev, "js interrupt, js=%d, status=%s, head=0x%x, tail=0x%x", 794 - j, exception_name, 795 - job_read(pfdev, JS_HEAD_LO(j)), 796 - job_read(pfdev, JS_TAIL_LO(j))); 797 - } else { 798 - dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x", 799 - j, exception_name, 800 - job_read(pfdev, JS_HEAD_LO(j)), 801 - job_read(pfdev, JS_TAIL_LO(j))); 802 - } 803 - 804 - /* If we need a reset, signal it to the timeout 805 - * handler, otherwise, update the fence error field and 806 - * signal the job fence. 807 - */ 808 - if (panfrost_exception_needs_reset(pfdev, js_status)) { 809 - drm_sched_fault(&pfdev->js->queue[j].sched); 810 - } else { 811 - int error = 0; 812 - 813 - if (js_status == DRM_PANFROST_EXCEPTION_TERMINATED) 814 - error = -ECANCELED; 815 - else if (panfrost_exception_is_fault(js_status)) 816 - error = -EINVAL; 817 - 818 - if (error) 819 - dma_fence_set_error(pfdev->jobs[j]->done_fence, error); 820 - 821 - status |= JOB_INT_MASK_DONE(j); 822 - } 823 - } 824 - 825 - if (status & JOB_INT_MASK_DONE(j)) { 826 - struct panfrost_job *job; 827 - 828 - job = pfdev->jobs[j]; 829 - /* The only reason this job could be NULL is if the 830 - * job IRQ handler is called just after the 831 - * in-flight job eviction in the reset path, and 832 - * this shouldn't happen because the job IRQ has 833 - * been masked and synchronized when this eviction 834 - * happens. 835 - */ 836 - WARN_ON(!job); 837 - if (job) { 838 - pfdev->jobs[j] = NULL; 839 - 840 - panfrost_mmu_as_put(pfdev, job->file_priv->mmu); 841 - panfrost_devfreq_record_idle(&pfdev->pfdevfreq); 842 - 843 - dma_fence_signal_locked(job->done_fence); 844 - pm_runtime_put_autosuspend(pfdev->dev); 845 - } 846 - } 847 - 848 - status &= ~mask; 849 - } 850 - } 851 - 852 470 static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data) 853 471 { 854 472 struct panfrost_device *pfdev = data; 855 - u32 status = job_read(pfdev, JOB_INT_RAWSTAT); 856 473 857 - while (status) { 858 - pm_runtime_mark_last_busy(pfdev->dev); 859 - 860 - spin_lock(&pfdev->js->job_lock); 861 - panfrost_job_handle_irq(pfdev, status); 862 - spin_unlock(&pfdev->js->job_lock); 863 - status = job_read(pfdev, JOB_INT_RAWSTAT); 864 - } 865 - 474 + panfrost_job_handle_irqs(pfdev); 866 475 job_write(pfdev, JOB_INT_MASK, 867 476 GENMASK(16 + NUM_JOB_SLOTS - 1, 16) | 868 477 GENMASK(NUM_JOB_SLOTS - 1, 0)); ··· 792 579 return IRQ_WAKE_THREAD; 793 580 } 794 581 795 - static void panfrost_reset_work(struct work_struct *work) 796 - { 797 - struct panfrost_device *pfdev = container_of(work, 798 - struct panfrost_device, 799 - reset.work); 800 - 801 - panfrost_reset(pfdev, NULL); 802 - } 803 - 804 582 int panfrost_job_init(struct panfrost_device *pfdev) 805 583 { 806 584 struct panfrost_job_slot *js; 585 + unsigned int nentries = 2; 807 586 int ret, j; 808 587 809 - INIT_WORK(&pfdev->reset.work, panfrost_reset_work); 588 + /* All GPUs have two entries per queue, but without jobchain 589 + * disambiguation stopping the right job in the close path is tricky, 590 + * so let's just advertise one entry in that case. 591 + */ 592 + if (!panfrost_has_hw_feature(pfdev, HW_FEATURE_JOBCHAIN_DISAMBIGUATION)) 593 + nentries = 1; 810 594 811 595 pfdev->js = js = devm_kzalloc(pfdev->dev, sizeof(*js), GFP_KERNEL); 812 596 if (!js) 813 597 return -ENOMEM; 814 598 599 + INIT_WORK(&pfdev->reset.work, panfrost_reset_work); 815 600 spin_lock_init(&js->job_lock); 816 601 817 602 js->irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "job"); ··· 835 624 836 625 ret = drm_sched_init(&js->queue[j].sched, 837 626 &panfrost_sched_ops, 838 - 1, 0, 627 + nentries, 0, 839 628 msecs_to_jiffies(JOB_TIMEOUT_MS), 840 629 pfdev->reset.wq, 841 630 NULL, "pan_js"); ··· 902 691 spin_lock(&pfdev->js->job_lock); 903 692 for (i = 0; i < NUM_JOB_SLOTS; i++) { 904 693 struct drm_sched_entity *entity = &panfrost_priv->sched_entity[i]; 905 - struct panfrost_job *job = pfdev->jobs[i]; 694 + int j; 906 695 907 - if (!job || job->base.entity != entity) 908 - continue; 696 + for (j = ARRAY_SIZE(pfdev->jobs[0]) - 1; j >= 0; j--) { 697 + struct panfrost_job *job = pfdev->jobs[i][j]; 698 + u32 cmd; 909 699 910 - job_write(pfdev, JS_COMMAND(i), JS_COMMAND_HARD_STOP); 700 + if (!job || job->base.entity != entity) 701 + continue; 702 + 703 + if (j == 1) { 704 + /* Try to cancel the job before it starts */ 705 + job_write(pfdev, JS_COMMAND_NEXT(i), JS_COMMAND_NOP); 706 + /* Reset the job head so it doesn't get restarted if 707 + * the job in the first slot failed. 708 + */ 709 + job->jc = 0; 710 + } 711 + 712 + if (panfrost_has_hw_feature(pfdev, HW_FEATURE_JOBCHAIN_DISAMBIGUATION)) { 713 + cmd = panfrost_get_job_chain_flag(job) ? 714 + JS_COMMAND_HARD_STOP_1 : 715 + JS_COMMAND_HARD_STOP_0; 716 + } else { 717 + cmd = JS_COMMAND_HARD_STOP; 718 + } 719 + 720 + job_write(pfdev, JS_COMMAND(i), cmd); 721 + } 911 722 } 912 723 spin_unlock(&pfdev->js->job_lock); 913 724 }