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.

Reviewed-by: Boris Brezillon <[email protected]>
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 b6a48ae0d3a6..c8c5dc26b03d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -492,6 +492,8 @@ bool panfrost_exception_needs_reset(const struct 
panfrost_device *pfdev,
 
 void panfrost_device_reset(struct panfrost_device *pfdev)
 {
+       guard(rwsem_write)(&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 c94546b49662..0570cb1d650d 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -165,6 +165,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 f77780c72a1a..571a26b84126 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 a3ff7d644276..e7ffbba58cf9 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -891,6 +891,7 @@ int panfrost_jm_init(struct panfrost_device *pfdev)
        INIT_WORK(&pfdev->reset.work, panfrost_reset_work);
        spin_lock_init(&js->job_lock);
        mutex_init(&pfdev->sched_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