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 <[email protected]>
---
 drivers/gpu/drm/panfrost/panfrost_device.c | 2 ++
 drivers/gpu/drm/panfrost/panfrost_device.h | 1 +
 drivers/gpu/drm/panfrost/panfrost_drv.c    | 9 ++++++---
 drivers/gpu/drm/panfrost/panfrost_job.c    | 1 +
 4 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c 
b/drivers/gpu/drm/panfrost/panfrost_device.c
index 5b66173c75b9..e0390b6c0d22 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -602,6 +602,8 @@ bool panfrost_exception_needs_reset(const struct 
panfrost_device *pfdev,
 
 void panfrost_device_reset(struct panfrost_device *pfdev, bool enable_job_int)
 {
+       guard(rwsem_read)(&pfdev->reset.lock);
+
        panfrost_gpu_soft_reset(pfdev);
        panfrost_gpu_power_on(pfdev);
        panfrost_mmu_reset(pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h 
b/drivers/gpu/drm/panfrost/panfrost_device.h
index 4bbaaaf827a5..a2a68e042225 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -166,6 +166,7 @@ struct panfrost_device {
        struct {
                struct workqueue_struct *wq;
                struct work_struct work;
+               struct rw_semaphore lock;
                atomic_t pending;
        } reset;
 
diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c 
b/drivers/gpu/drm/panfrost/panfrost_drv.c
index 958f1d36ab10..ff23b1a979bb 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 c761379851da..9d7dafa29f19 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -874,6 +874,7 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
 
        INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
        spin_lock_init(&js->job_lock);
+       init_rwsem(&pfdev->reset.lock);
 
        js->irq = platform_get_irq_byname(to_platform_device(pfdev->base.dev), 
"job");
        if (js->irq < 0)

-- 
2.55.0

Reply via email to