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

drm/panfrost: Kill in-flight jobs on FD close

If the process who submitted these jobs decided to close the FD before
the jobs are done it probably means it doesn't care about the result.

v5:
* Add a panfrost_exception_is_fault() helper and the
DRM_PANFROST_EXCEPTION_MAX_NON_FAULT value

v4:
* Don't disable/restore irqs when taking the job_lock (not needed since
this lock is never taken from an interrupt context)

v3:
* Set fence error to ECANCELED when a TERMINATED exception is received

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-15-boris.brezillon@collabora.com

+43 -6
+7
drivers/gpu/drm/panfrost/panfrost_device.h
··· 184 184 DRM_PANFROST_EXCEPTION_KABOOM = 0x05, 185 185 DRM_PANFROST_EXCEPTION_EUREKA = 0x06, 186 186 DRM_PANFROST_EXCEPTION_ACTIVE = 0x08, 187 + DRM_PANFROST_EXCEPTION_MAX_NON_FAULT = 0x3f, 187 188 DRM_PANFROST_EXCEPTION_JOB_CONFIG_FAULT = 0x40, 188 189 DRM_PANFROST_EXCEPTION_JOB_POWER_FAULT = 0x41, 189 190 DRM_PANFROST_EXCEPTION_JOB_READ_FAULT = 0x42, ··· 244 243 DRM_PANFROST_EXCEPTION_MEM_ATTR_NONCACHE_2 = 0xee, 245 244 DRM_PANFROST_EXCEPTION_MEM_ATTR_NONCACHE_3 = 0xef, 246 245 }; 246 + 247 + static inline bool 248 + panfrost_exception_is_fault(u32 exception_code) 249 + { 250 + return exception_code > DRM_PANFROST_EXCEPTION_MAX_NON_FAULT; 251 + } 247 252 248 253 const char *panfrost_exception_name(u32 exception_code); 249 254 bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
+36 -6
drivers/gpu/drm/panfrost/panfrost_job.c
··· 483 483 484 484 if (status & JOB_INT_MASK_ERR(j)) { 485 485 u32 js_status = job_read(pfdev, JS_STATUS(j)); 486 + const char *exception_name = panfrost_exception_name(js_status); 486 487 487 488 job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_NOP); 488 489 489 - dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x", 490 - j, 491 - panfrost_exception_name(js_status), 492 - job_read(pfdev, JS_HEAD_LO(j)), 493 - job_read(pfdev, JS_TAIL_LO(j))); 490 + if (!panfrost_exception_is_fault(js_status)) { 491 + dev_dbg(pfdev->dev, "js interrupt, js=%d, status=%s, head=0x%x, tail=0x%x", 492 + j, exception_name, 493 + job_read(pfdev, JS_HEAD_LO(j)), 494 + job_read(pfdev, JS_TAIL_LO(j))); 495 + } else { 496 + dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x", 497 + j, exception_name, 498 + job_read(pfdev, JS_HEAD_LO(j)), 499 + job_read(pfdev, JS_TAIL_LO(j))); 500 + } 494 501 495 502 /* If we need a reset, signal it to the timeout 496 503 * handler, otherwise, update the fence error field and ··· 506 499 if (panfrost_exception_needs_reset(pfdev, js_status)) { 507 500 drm_sched_fault(&pfdev->js->queue[j].sched); 508 501 } else { 509 - dma_fence_set_error(pfdev->jobs[j]->done_fence, -EINVAL); 502 + int error = 0; 503 + 504 + if (js_status == DRM_PANFROST_EXCEPTION_TERMINATED) 505 + error = -ECANCELED; 506 + else if (panfrost_exception_is_fault(js_status)) 507 + error = -EINVAL; 508 + 509 + if (error) 510 + dma_fence_set_error(pfdev->jobs[j]->done_fence, error); 511 + 510 512 status |= JOB_INT_MASK_DONE(j); 511 513 } 512 514 } ··· 681 665 682 666 void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) 683 667 { 668 + struct panfrost_device *pfdev = panfrost_priv->pfdev; 684 669 int i; 685 670 686 671 for (i = 0; i < NUM_JOB_SLOTS; i++) 687 672 drm_sched_entity_destroy(&panfrost_priv->sched_entity[i]); 673 + 674 + /* Kill in-flight jobs */ 675 + spin_lock(&pfdev->js->job_lock); 676 + for (i = 0; i < NUM_JOB_SLOTS; i++) { 677 + struct drm_sched_entity *entity = &panfrost_priv->sched_entity[i]; 678 + struct panfrost_job *job = pfdev->jobs[i]; 679 + 680 + if (!job || job->base.entity != entity) 681 + continue; 682 + 683 + job_write(pfdev, JS_COMMAND(i), JS_COMMAND_HARD_STOP); 684 + } 685 + spin_unlock(&pfdev->js->job_lock); 688 686 } 689 687 690 688 int panfrost_job_is_idle(struct panfrost_device *pfdev)