diff options
| author | Rob Herring (Arm) <robh@kernel.org> | 2026-02-18 16:21:55 -0600 |
|---|---|---|
| committer | Rob Herring (Arm) <robh@kernel.org> | 2026-03-05 15:21:17 -0600 |
| commit | 150bceb3e0a4a30950279d91ea0e8cc69a736742 (patch) | |
| tree | a0aea57285e630ca9665421e8bdec9015160a034 | |
| parent | d5b8b0347fa8470b751a506fb801797e271d7548 (diff) | |
accel: ethosu: Fix job submit error clean-up refcount underflows
If the job submit fails before adding the job to the scheduler queue
such as when the GEM buffer bounds checks fail, then doing a
ethosu_job_put() results in a pm_runtime_put_autosuspend() without the
corresponding pm_runtime_resume_and_get(). The dma_fence_put()'s are
also unnecessary, but seem to be harmless.
Split the ethosu_job_cleanup() function into 2 parts for the before
and after the job is queued.
Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver")
Reviewed-and-Tested-by: Anders Roxell <anders.roxell@linaro.org>
Link: https://patch.msgid.link/20260218-ethos-fixes-v1-1-be3fa3ea9a30@kernel.org
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
| -rw-r--r-- | drivers/accel/ethosu/ethosu_job.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c index 8598a3634340..ec85f4156744 100644 --- a/drivers/accel/ethosu/ethosu_job.c +++ b/drivers/accel/ethosu/ethosu_job.c @@ -143,23 +143,29 @@ out: return ret; } +static void ethosu_job_err_cleanup(struct ethosu_job *job) +{ + unsigned int i; + + for (i = 0; i < job->region_cnt; i++) + drm_gem_object_put(job->region_bo[i]); + + drm_gem_object_put(job->cmd_bo); + + kfree(job); +} + static void ethosu_job_cleanup(struct kref *ref) { struct ethosu_job *job = container_of(ref, struct ethosu_job, refcount); - unsigned int i; pm_runtime_put_autosuspend(job->dev->base.dev); dma_fence_put(job->done_fence); dma_fence_put(job->inference_done_fence); - for (i = 0; i < job->region_cnt; i++) - drm_gem_object_put(job->region_bo[i]); - - drm_gem_object_put(job->cmd_bo); - - kfree(job); + ethosu_job_err_cleanup(job); } static void ethosu_job_put(struct ethosu_job *job) @@ -454,12 +460,16 @@ static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file } } ret = ethosu_job_push(ejob); + if (!ret) { + ethosu_job_put(ejob); + return 0; + } out_cleanup_job: if (ret) drm_sched_job_cleanup(&ejob->base); out_put_job: - ethosu_job_put(ejob); + ethosu_job_err_cleanup(ejob); return ret; } |
