[PATCH v4 08/13] drm/panfrost: Rewire reset sequence to avoid concurrent attempts

From: Adrián Larumbe

Date: Tue Jul 28 2026 - 23:00:40 EST


This way, and in imitation of Panthor, only a single reset thread can
progress at a time, and other threads wanting to trigger it just wait
on the ongoing one to finish and wake them up.

Signed-off-by: Adrián Larumbe <adrian.larumbe@xxxxxxxxxxxxx>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 1 +
drivers/gpu/drm/panfrost/panfrost_device.h | 5 +++--
drivers/gpu/drm/panfrost/panfrost_job.c | 7 ++++---
3 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index a9d29d9ee22b..a51f1ef8563c 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -8,6 +8,7 @@
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
+#include <linux/wait.h>

#include "panfrost_device.h"
#include "panfrost_devfreq.h"
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index eeca57efcbec..f0acfc634cd4 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -167,6 +167,7 @@ struct panfrost_device {
struct {
struct workqueue_struct *wq;
struct work_struct work;
+ wait_queue_head_t wait;
atomic_t pending;
} reset;

@@ -341,8 +342,8 @@ bool panfrost_exception_needs_reset(const struct panfrost_device *pfdev,
static inline void
panfrost_device_schedule_reset(struct panfrost_device *pfdev)
{
- atomic_set(&pfdev->reset.pending, 1);
- queue_work(pfdev->reset.wq, &pfdev->reset.work);
+ if (!atomic_cmpxchg(&pfdev->reset.pending, 0, 1))
+ queue_work(pfdev->reset.wq, &pfdev->reset.work);
}

static inline bool
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index bda1494eb430..ed8a1fabd47b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -499,10 +499,8 @@ static void panfrost_job_handle_err(struct panfrost_device *pfdev,

pm_runtime_put_autosuspend(pfdev->base.dev);

- if (panfrost_exception_needs_reset(pfdev, js_status)) {
- atomic_set(&pfdev->reset.pending, 1);
+ if (panfrost_exception_needs_reset(pfdev, js_status))
drm_sched_fault(&pfdev->js->queue[js].sched);
- }
}

static void panfrost_jm_handle_done(struct panfrost_device *pfdev,
@@ -757,6 +755,8 @@ panfrost_reset(struct panfrost_device *pfdev,
panfrost_jm_enable_interrupts(pfdev);

dma_fence_end_signalling(cookie);
+
+ wake_up_all(&pfdev->reset.wait);
}

static enum drm_gpu_sched_stat panfrost_job_timedout(struct drm_sched_job
@@ -893,6 +893,7 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
if (!pfdev->reset.wq)
return -ENOMEM;
args.timeout_wq = pfdev->reset.wq;
+ init_waitqueue_head(&pfdev->reset.wait);

for (j = 0; j < NUM_JOB_SLOTS; j++) {
js->queue[j].fence_context = dma_fence_context_alloc(1);

--
2.55.0