Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/v3d: Refcount v3d_stats

Convert `v3d_stats` from embedded structs to heap-allocated, refcounted
objects. This decouples the stats lifetime from the containing
structures (this is, `v3d_queue_state` and `v3d_file_priv`), allowing
jobs to safely hold their own references to stats objects even after the
file descriptor is closed.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-by: Iago Toral Quiroga <itoral@igalia.com>
Link: https://patch.msgid.link/20260306-v3d-reset-locking-improv-v3-3-49864fe00692@igalia.com
Co-developed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maíra Canal <mcanal@igalia.com>

authored by

Tvrtko Ursulin and committed by
Maíra Canal
266d4ba3 0b2a4569

+84 -27
+14 -5
drivers/gpu/drm/v3d/v3d_drv.c
··· 140 140 v3d_priv->v3d = v3d; 141 141 142 142 for (i = 0; i < V3D_MAX_QUEUES; i++) { 143 + v3d_priv->stats[i] = v3d_stats_alloc(); 144 + if (!v3d_priv->stats[i]) { 145 + ret = -ENOMEM; 146 + goto err_stats; 147 + } 148 + 143 149 sched = &v3d->queue[i].sched; 144 150 ret = drm_sched_entity_init(&v3d_priv->sched_entity[i], 145 151 DRM_SCHED_PRIORITY_NORMAL, &sched, 146 152 1, NULL); 147 153 if (ret) 148 154 goto err_sched; 149 - 150 - memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i])); 151 - seqcount_init(&v3d_priv->stats[i].lock); 152 155 } 153 156 154 157 v3d_perfmon_open_file(v3d_priv); ··· 160 157 return 0; 161 158 162 159 err_sched: 163 - for (i--; i >= 0; i--) 160 + v3d_stats_put(v3d_priv->stats[i]); 161 + err_stats: 162 + for (i--; i >= 0; i--) { 164 163 drm_sched_entity_destroy(&v3d_priv->sched_entity[i]); 164 + v3d_stats_put(v3d_priv->stats[i]); 165 + } 165 166 kfree(v3d_priv); 166 167 return ret; 167 168 } ··· 189 182 job->file_priv = NULL; 190 183 spin_unlock_irqrestore(&queue->queue_lock, irqflags); 191 184 } 185 + 186 + v3d_stats_put(v3d_priv->stats[q]); 192 187 } 193 188 194 189 v3d_perfmon_close_file(v3d_priv); ··· 218 209 enum v3d_queue queue; 219 210 220 211 for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { 221 - struct v3d_stats *stats = &file_priv->stats[queue]; 212 + struct v3d_stats *stats = file_priv->stats[queue]; 222 213 u64 active_runtime, jobs_completed; 223 214 224 215 v3d_get_stats(stats, timestamp, &active_runtime, &jobs_completed);
+17 -2
drivers/gpu/drm/v3d/v3d_drv.h
··· 38 38 } 39 39 40 40 struct v3d_stats { 41 + struct kref refcount; 42 + 41 43 u64 start_ns; 42 44 u64 enabled_ns; 43 45 u64 jobs_completed; ··· 64 62 u64 emit_seqno; 65 63 66 64 /* Stores the GPU stats for this queue in the global context. */ 67 - struct v3d_stats stats; 65 + struct v3d_stats *stats; 68 66 69 67 /* Currently active job for this queue */ 70 68 struct v3d_job *active_job; ··· 232 230 struct drm_sched_entity sched_entity[V3D_MAX_QUEUES]; 233 231 234 232 /* Stores the GPU stats for a specific queue for this fd. */ 235 - struct v3d_stats stats[V3D_MAX_QUEUES]; 233 + struct v3d_stats *stats[V3D_MAX_QUEUES]; 236 234 237 235 /* Per-fd reset counter, must be incremented when a job submitted 238 236 * by this fd causes a GPU reset. It must be protected by ··· 605 603 unsigned int count); 606 604 void v3d_performance_query_info_free(struct v3d_performance_query_info *query_info, 607 605 unsigned int count); 606 + struct v3d_stats *v3d_stats_alloc(void); 607 + void v3d_stats_release(struct kref *refcount); 608 608 void v3d_job_update_stats(struct v3d_job *job, enum v3d_queue q); 609 609 int v3d_sched_init(struct v3d_dev *v3d); 610 610 void v3d_sched_fini(struct v3d_dev *v3d); 611 + 612 + static inline struct v3d_stats *v3d_stats_get(struct v3d_stats *stats) 613 + { 614 + kref_get(&stats->refcount); 615 + return stats; 616 + } 617 + 618 + static inline void v3d_stats_put(struct v3d_stats *stats) 619 + { 620 + kref_put(&stats->refcount, v3d_stats_release); 621 + } 611 622 612 623 /* v3d_perfmon.c */ 613 624 void v3d_perfmon_init(struct v3d_dev *v3d);
+27 -15
drivers/gpu/drm/v3d/v3d_gem.c
··· 287 287 for (i = 0; i < V3D_MAX_QUEUES; i++) { 288 288 struct v3d_queue_state *queue = &v3d->queue[i]; 289 289 290 + queue->stats = v3d_stats_alloc(); 291 + if (!queue->stats) { 292 + ret = -ENOMEM; 293 + goto err_stats; 294 + } 295 + 290 296 queue->fence_context = dma_fence_context_alloc(1); 291 - memset(&queue->stats, 0, sizeof(queue->stats)); 292 - seqcount_init(&queue->stats.lock); 293 297 294 298 spin_lock_init(&queue->queue_lock); 295 299 spin_lock_init(&queue->fence_lock); ··· 302 298 spin_lock_init(&v3d->mm_lock); 303 299 ret = drmm_mutex_init(dev, &v3d->bo_lock); 304 300 if (ret) 305 - return ret; 301 + goto err_stats; 306 302 ret = drmm_mutex_init(dev, &v3d->reset_lock); 307 303 if (ret) 308 - return ret; 304 + goto err_stats; 309 305 ret = drmm_mutex_init(dev, &v3d->sched_lock); 310 306 if (ret) 311 - return ret; 307 + goto err_stats; 312 308 ret = drmm_mutex_init(dev, &v3d->cache_clean_lock); 313 309 if (ret) 314 - return ret; 310 + goto err_stats; 315 311 316 312 /* Note: We don't allocate address 0. Various bits of HW 317 313 * treat 0 as special, such as the occlusion query counters ··· 323 319 &v3d->pt_paddr, 324 320 GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO); 325 321 if (!v3d->pt) { 326 - drm_mm_takedown(&v3d->mm); 327 322 dev_err(v3d->drm.dev, 328 323 "Failed to allocate page tables. Please ensure you have DMA enabled.\n"); 329 - return -ENOMEM; 324 + ret = -ENOMEM; 325 + goto err_dma_alloc; 330 326 } 331 327 332 328 v3d_init_hw_state(v3d); ··· 335 331 v3d_huge_mnt_init(v3d); 336 332 337 333 ret = v3d_sched_init(v3d); 338 - if (ret) { 339 - drm_mm_takedown(&v3d->mm); 340 - dma_free_coherent(v3d->drm.dev, pt_size, (void *)v3d->pt, 341 - v3d->pt_paddr); 342 - return ret; 343 - } 334 + if (ret) 335 + goto err_sched; 344 336 345 337 return 0; 338 + 339 + err_sched: 340 + dma_free_coherent(v3d->drm.dev, pt_size, (void *)v3d->pt, v3d->pt_paddr); 341 + err_dma_alloc: 342 + drm_mm_takedown(&v3d->mm); 343 + err_stats: 344 + for (i--; i >= 0; i--) 345 + v3d_stats_put(v3d->queue[i].stats); 346 + 347 + return ret; 346 348 } 347 349 348 350 void ··· 362 352 /* Waiting for jobs to finish would need to be done before 363 353 * unregistering V3D. 364 354 */ 365 - for (q = 0; q < V3D_MAX_QUEUES; q++) 355 + for (q = 0; q < V3D_MAX_QUEUES; q++) { 366 356 WARN_ON(v3d->queue[q].active_job); 357 + v3d_stats_put(v3d->queue[q].stats); 358 + } 367 359 368 360 drm_mm_takedown(&v3d->mm); 369 361
+25 -4
drivers/gpu/drm/v3d/v3d_sched.c
··· 66 66 return container_of(sched_job, struct v3d_cpu_job, base.base); 67 67 } 68 68 69 + void v3d_stats_release(struct kref *refcount) 70 + { 71 + struct v3d_stats *stats = container_of(refcount, typeof(*stats), refcount); 72 + 73 + kfree(stats); 74 + } 75 + 76 + struct v3d_stats *v3d_stats_alloc(void) 77 + { 78 + struct v3d_stats *stats; 79 + 80 + stats = kzalloc_obj(*stats); 81 + if (!stats) 82 + return NULL; 83 + 84 + kref_init(&stats->refcount); 85 + seqcount_init(&stats->lock); 86 + 87 + return stats; 88 + } 89 + 69 90 static void 70 91 v3d_sched_job_free(struct drm_sched_job *sched_job) 71 92 { ··· 162 141 { 163 142 struct v3d_dev *v3d = job->v3d; 164 143 struct v3d_file_priv *file = job->file_priv; 165 - struct v3d_stats *global_stats = &v3d->queue[queue].stats; 166 - struct v3d_stats *local_stats = &file->stats[queue]; 144 + struct v3d_stats *global_stats = v3d->queue[queue].stats; 145 + struct v3d_stats *local_stats = file->stats[queue]; 167 146 u64 now = local_clock(); 168 147 169 148 preempt_disable(); ··· 194 173 { 195 174 struct v3d_dev *v3d = job->v3d; 196 175 struct v3d_queue_state *queue = &v3d->queue[q]; 197 - struct v3d_stats *global_stats = &queue->stats; 176 + struct v3d_stats *global_stats = queue->stats; 198 177 u64 now = local_clock(); 199 178 200 179 preempt_disable(); ··· 202 181 /* Don't update the local stats if the file context has already closed */ 203 182 spin_lock(&queue->queue_lock); 204 183 if (job->file_priv) 205 - v3d_stats_update(&job->file_priv->stats[q], now); 184 + v3d_stats_update(job->file_priv->stats[q], now); 206 185 spin_unlock(&queue->queue_lock); 207 186 208 187 v3d_stats_update(global_stats, now);
+1 -1
drivers/gpu/drm/v3d/v3d_sysfs.c
··· 20 20 len += sysfs_emit(buf, "queue\ttimestamp\tjobs\truntime\n"); 21 21 22 22 for (queue = 0; queue < V3D_MAX_QUEUES; queue++) { 23 - struct v3d_stats *stats = &v3d->queue[queue].stats; 23 + struct v3d_stats *stats = v3d->queue[queue].stats; 24 24 u64 active_runtime, jobs_completed; 25 25 26 26 v3d_get_stats(stats, timestamp, &active_runtime, &jobs_completed);