[PATCH 1/3] accel: ethosu: Fix job submit error clean-up refcount underflows

Rob Herring (Arm) posted 3 patches 1 month, 1 week ago
[PATCH 1/3] accel: ethosu: Fix job submit error clean-up refcount underflows
Posted by Rob Herring (Arm) 1 month, 1 week ago
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")
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
 drivers/accel/ethosu/ethosu_job.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c
index 26e7a2f64d71..70a144803b09 100644
--- a/drivers/accel/ethosu/ethosu_job.c
+++ b/drivers/accel/ethosu/ethosu_job.c
@@ -143,23 +143,29 @@ static int ethosu_job_push(struct ethosu_job *job)
 	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;
 }

-- 
2.51.0
Re: [PATCH 1/3] accel: ethosu: Fix job submit error clean-up refcount underflows
Posted by Anders Roxell 1 month, 1 week ago
On Wed, 18 Feb 2026 at 23:22, Rob Herring (Arm) <robh@kernel.org> wrote:
>
> 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")
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>

Reviewed-and-Tested-by: Anders Roxell <anders.roxell@linaro.org>

> ---
>  drivers/accel/ethosu/ethosu_job.c | 26 ++++++++++++++++++--------
>  1 file changed, 18 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c
> index 26e7a2f64d71..70a144803b09 100644
> --- a/drivers/accel/ethosu/ethosu_job.c
> +++ b/drivers/accel/ethosu/ethosu_job.c
> @@ -143,23 +143,29 @@ static int ethosu_job_push(struct ethosu_job *job)
>         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;
>  }
>
> --
> 2.51.0
>