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 0c8f53905da8..ce1d3eb40332 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -491,6 +491,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 087905cd347a..6107485a5332 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -876,6 +876,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
