[PATCH v4 11/13] drm/panfrost: Introduce a reset lock

From: Adrián Larumbe

Date: Tue Jul 28 2026 - 23:02:08 EST


So as to avoid accessing HW register while a reset is ongoing, a read/write
semaphore that envelopes the reset sequence will help driver entry points
avoid racing with it. For now, the only such racy entry point is the ioctl
that returns the current GPU timestmap.

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

diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index c0334b72c70b..926bdf21389f 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -615,6 +615,10 @@ void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
{
int ret;

+ /* Pre-reset */
+ if (panfrost_device_started(pfdev))
+ down_write(&pfdev->reset.lock);
+
/* Do the actual device reset */
ret = panfrost_gpu_soft_reset(pfdev);
panfrost_gpu_power_on(pfdev);
@@ -625,6 +629,7 @@ void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
panfrost_jm_reset_interrupts(pfdev);
if (enable_job_int)
panfrost_jm_enable_interrupts(pfdev);
+ up_write(&pfdev->reset.lock);
}

if (!panfrost_device_started(pfdev) && !ret)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index f96ba50dfa91..81f2290d3e86 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;
+ struct rw_semaphore lock;
wait_queue_head_t wait;
atomic_t pending;
} reset;
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c
index fac5be20ad60..3212dbadcdb8 100644
--- a/drivers/gpu/drm/panfrost/panfrost_drv.c
+++ b/drivers/gpu/drm/panfrost/panfrost_drv.c
@@ -41,9 +41,12 @@ static int panfrost_ioctl_query_timestamp(struct panfrost_device *pfdev,
if (ret)
return ret;

- panfrost_cycle_counter_get(pfdev);
- *arg = panfrost_timestamp_read(pfdev);
- panfrost_cycle_counter_put(pfdev);
+ /* We should not read timestamp register while the GPU is being reset */
+ scoped_guard(rwsem_read, &pfdev->reset.lock) {
+ panfrost_cycle_counter_get(pfdev);
+ *arg = panfrost_timestamp_read(pfdev);
+ panfrost_cycle_counter_put(pfdev);
+ }

pm_runtime_put(pfdev->base.dev);
return 0;
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index ed8a1fabd47b..f40563682860 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -893,7 +893,9 @@ 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);
+ init_rwsem(&pfdev->reset.lock);

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

--
2.55.0