From: Tvrtko Ursulin Date: Fri, 6 Mar 2026 11:30:37 +0000 (-0300) Subject: drm/v3d: Attach per-fd reset counters to v3d_stats X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2f0e110735a4e59e71e44d04b4f70e58f06c61c9;p=thirdparty%2Fkernel%2Flinux.git drm/v3d: Attach per-fd reset counters to v3d_stats To remove the file_priv NULL-ing dance needed to check if the file descriptor is open, move the per-fd reset counter into v3d_stats, which is heap-allocated and refcounted, outliving the fd as long as jobs reference it. This change allows the removal of the last `queue_lock` usage to protect `job->file_priv` and avoids possible NULL ptr dereference issues due to lifetime mismatches. Also, to simplify locking, replace both the global and per-fd locked reset counters with atomics. Signed-off-by: Tvrtko Ursulin Reviewed-by: Iago Toral Quiroga Link: https://patch.msgid.link/20260306-v3d-reset-locking-improv-v3-5-49864fe00692@igalia.com Co-developed-by: Maíra Canal Signed-off-by: Maíra Canal --- diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c index 0f5e29f57fa59..4b441afcb602d 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.c +++ b/drivers/gpu/drm/v3d/v3d_drv.c @@ -110,14 +110,12 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data, args->value = !!drm_gem_get_huge_mnt(dev); return 0; case DRM_V3D_PARAM_GLOBAL_RESET_COUNTER: - mutex_lock(&v3d->reset_lock); - args->value = v3d->reset_counter; - mutex_unlock(&v3d->reset_lock); + args->value = atomic_read(&v3d->reset_counter); return 0; case DRM_V3D_PARAM_CONTEXT_RESET_COUNTER: - mutex_lock(&v3d->reset_lock); - args->value = v3d_priv->reset_counter; - mutex_unlock(&v3d->reset_lock); + args->value = 0; + for (enum v3d_queue q = 0; q < V3D_MAX_QUEUES; q++) + args->value += atomic_read(&v3d_priv->stats[q]->reset_counter); return 0; default: drm_dbg(dev, "Unknown parameter %d\n", args->param); @@ -173,23 +171,11 @@ err_stats: static void v3d_postclose(struct drm_device *dev, struct drm_file *file) { - struct v3d_dev *v3d = to_v3d_dev(dev); struct v3d_file_priv *v3d_priv = file->driver_priv; - unsigned long irqflags; enum v3d_queue q; for (q = 0; q < V3D_MAX_QUEUES; q++) { - struct v3d_queue_state *queue = &v3d->queue[q]; - struct v3d_job *job = queue->active_job; - drm_sched_entity_destroy(&v3d_priv->sched_entity[q]); - - if (job && job->base.entity == &v3d_priv->sched_entity[q]) { - spin_lock_irqsave(&queue->queue_lock, irqflags); - job->file_priv = NULL; - spin_unlock_irqrestore(&queue->queue_lock, irqflags); - } - v3d_stats_put(v3d_priv->stats[q]); } diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 72c3f40715dae..3de485abd8fc2 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -55,6 +55,8 @@ struct v3d_stats { * job queues, even the write side never is. */ seqcount_t lock; + + atomic_t reset_counter; }; struct v3d_queue_state { @@ -203,10 +205,8 @@ struct v3d_dev { */ struct v3d_perfmon *global_perfmon; - /* Global reset counter. The counter must be incremented when - * a GPU reset happens. It must be protected by @reset_lock. - */ - unsigned int reset_counter; + /* Global reset counter incremented on each GPU reset. */ + atomic_t reset_counter; }; static inline struct v3d_dev * @@ -233,12 +233,6 @@ struct v3d_file_priv { /* Stores the GPU stats for a specific queue for this fd. */ struct v3d_stats *stats[V3D_MAX_QUEUES]; - - /* Per-fd reset counter, must be incremented when a job submitted - * by this fd causes a GPU reset. It must be protected by - * &struct v3d_dev->reset_lock. - */ - unsigned int reset_counter; }; struct v3d_bo { diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c index 5c387a152e33f..1855ef5b3b5fe 100644 --- a/drivers/gpu/drm/v3d/v3d_sched.c +++ b/drivers/gpu/drm/v3d/v3d_sched.c @@ -701,8 +701,6 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job, enum v3d_queue q) { struct v3d_job *job = to_v3d_job(sched_job); - struct v3d_file_priv *v3d_priv = job->file_priv; - unsigned long irqflags; enum v3d_queue i; mutex_lock(&v3d->reset_lock); @@ -717,11 +715,8 @@ v3d_gpu_reset_for_timeout(struct v3d_dev *v3d, struct drm_sched_job *sched_job, /* get the GPU back into the init state */ v3d_reset(v3d); - v3d->reset_counter++; - spin_lock_irqsave(&v3d->queue[q].queue_lock, irqflags); - if (v3d_priv) - v3d_priv->reset_counter++; - spin_unlock_irqrestore(&v3d->queue[q].queue_lock, irqflags); + atomic_inc(&v3d->reset_counter); + atomic_inc(&job->client_stats->reset_counter); for (i = 0; i < V3D_MAX_QUEUES; i++) drm_sched_resubmit_jobs(&v3d->queue[i].sched);