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 <[email protected]>
---
 drivers/gpu/drm/panfrost/panfrost_device.c |  1 +
 drivers/gpu/drm/panfrost/panfrost_device.h |  5 +++--
 drivers/gpu/drm/panfrost/panfrost_job.c    | 16 ++++++++++------
 3 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c 
b/drivers/gpu/drm/panfrost/panfrost_device.c
index d68f1ec82895..cf115db9cebf 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 6bec8fcb701e..23dea923bd04 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);
 }
 
 #endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c 
b/drivers/gpu/drm/panfrost/panfrost_job.c
index 2d12b83e900a..c2a1670a74e8 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -497,10 +497,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,
@@ -755,6 +753,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
@@ -763,6 +763,7 @@ static enum drm_gpu_sched_stat panfrost_job_timedout(struct 
drm_sched_job
        struct panfrost_job *job = to_panfrost_job(sched_job);
        struct panfrost_device *pfdev = job->pfdev;
        int js = panfrost_job_get_slot(job);
+       int ret;
 
        /*
         * If the GPU managed to complete this jobs fence, the timeout has
@@ -797,10 +798,12 @@ static enum drm_gpu_sched_stat 
panfrost_job_timedout(struct drm_sched_job
 
        panfrost_core_dump(job);
 
-       atomic_set(&pfdev->reset.pending, 1);
-       panfrost_reset(pfdev, sched_job);
+       panfrost_device_schedule_reset(pfdev);
+       ret = wait_event_timeout(pfdev->reset.wait,
+                                !atomic_read(&pfdev->reset.pending),
+                                msecs_to_jiffies(60));
 
-       return DRM_GPU_SCHED_STAT_RESET;
+       return (ret) ? DRM_GPU_SCHED_STAT_RESET : DRM_GPU_SCHED_STAT_ENODEV;
 }
 
 static void panfrost_reset_work(struct work_struct *work)
@@ -892,6 +895,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

Reply via email to