Commit 150bceb3 authored by Rob Herring (Arm)'s avatar Rob Herring (Arm)
Browse files

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: 5a5e9c02 ("accel: Add Arm Ethos-U NPU driver")
Reviewed-and-Tested-by: default avatarAnders Roxell <anders.roxell@linaro.org>
Link: https://patch.msgid.link/20260218-ethos-fixes-v1-1-be3fa3ea9a30@kernel.org


Signed-off-by: default avatarRob Herring (Arm) <robh@kernel.org>
parent d5b8b034
Loading
Loading
Loading
Loading
+18 −8
Original line number Diff line number Diff line
@@ -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;
}