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

drm/panthor: show device-wide list of DRM GEM objects over DebugFS

Add a device DebugFS file that displays a complete list of all the DRM
GEM objects that are exposed to UM through a DRM handle.

Since leaking object identifiers that might belong to a different NS is
inadmissible, this functionality is only made available in debug builds
with DEBUGFS support enabled.

File format is that of a table, with each entry displaying a variety of
fields with information about each GEM object.

Each GEM object entry in the file displays the following information
fields: Client PID, BO's global name, reference count, BO virtual size,
BO resize size, VM address in its DRM-managed range, BO label and a GEM
state flags.

There's also a usage flags field for the type of BO, which tells us
whether it's a kernel BO and/or mapped onto the FW's address space.

GEM state and usage flag meanings are printed in the file prelude, so
that UM parsing tools can interpret the numerical values in the table.

Signed-off-by: Adrián Larumbe <adrian.larumbe@collabora.com>
Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Link: https://lore.kernel.org/r/20250423021238.1639175-5-adrian.larumbe@collabora.com
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>

authored by

Adrián Larumbe and committed by
Boris Brezillon
a3707f53 0489149f

+262
+5
drivers/gpu/drm/panthor/panthor_device.c
··· 180 180 if (ret) 181 181 return ret; 182 182 183 + #ifdef CONFIG_DEBUG_FS 184 + drmm_mutex_init(&ptdev->base, &ptdev->gems.lock); 185 + INIT_LIST_HEAD(&ptdev->gems.node); 186 + #endif 187 + 183 188 atomic_set(&ptdev->pm.state, PANTHOR_DEVICE_PM_STATE_SUSPENDED); 184 189 p = alloc_page(GFP_KERNEL | __GFP_ZERO); 185 190 if (!p)
+11
drivers/gpu/drm/panthor/panthor_device.h
··· 205 205 206 206 /** @fast_rate: Maximum device clock frequency. Set by DVFS */ 207 207 unsigned long fast_rate; 208 + 209 + #ifdef CONFIG_DEBUG_FS 210 + /** @gems: Device-wide list of GEM objects owned by at least one file. */ 211 + struct { 212 + /** @gems.lock: Protects the device-wide list of GEM objects. */ 213 + struct mutex lock; 214 + 215 + /** @node: Used to keep track of all the device's DRM objects */ 216 + struct list_head node; 217 + } gems; 218 + #endif 208 219 }; 209 220 210 221 struct panthor_gpu_usage {
+25
drivers/gpu/drm/panthor/panthor_drv.c
··· 1544 1544 }; 1545 1545 1546 1546 #ifdef CONFIG_DEBUG_FS 1547 + static int panthor_gems_show(struct seq_file *m, void *data) 1548 + { 1549 + struct drm_info_node *node = m->private; 1550 + struct drm_device *dev = node->minor->dev; 1551 + struct panthor_device *ptdev = container_of(dev, struct panthor_device, base); 1552 + 1553 + panthor_gem_debugfs_print_bos(ptdev, m); 1554 + 1555 + return 0; 1556 + } 1557 + 1558 + static struct drm_info_list panthor_debugfs_list[] = { 1559 + {"gems", panthor_gems_show, 0, NULL}, 1560 + }; 1561 + 1562 + static int panthor_gems_debugfs_init(struct drm_minor *minor) 1563 + { 1564 + drm_debugfs_create_files(panthor_debugfs_list, 1565 + ARRAY_SIZE(panthor_debugfs_list), 1566 + minor->debugfs_root, minor); 1567 + 1568 + return 0; 1569 + } 1570 + 1547 1571 static void panthor_debugfs_init(struct drm_minor *minor) 1548 1572 { 1549 1573 panthor_mmu_debugfs_init(minor); 1574 + panthor_gems_debugfs_init(minor); 1550 1575 } 1551 1576 #endif 1552 1577
+156
drivers/gpu/drm/panthor/panthor_gem.c
··· 11 11 #include <drm/panthor_drm.h> 12 12 13 13 #include "panthor_device.h" 14 + #include "panthor_fw.h" 14 15 #include "panthor_gem.h" 15 16 #include "panthor_mmu.h" 17 + 18 + #ifdef CONFIG_DEBUG_FS 19 + static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev, 20 + struct panthor_gem_object *bo) 21 + { 22 + INIT_LIST_HEAD(&bo->debugfs.node); 23 + 24 + bo->debugfs.creator.tgid = current->group_leader->pid; 25 + get_task_comm(bo->debugfs.creator.process_name, current->group_leader); 26 + 27 + mutex_lock(&ptdev->gems.lock); 28 + list_add_tail(&bo->debugfs.node, &ptdev->gems.node); 29 + mutex_unlock(&ptdev->gems.lock); 30 + } 31 + 32 + static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) 33 + { 34 + struct panthor_device *ptdev = container_of(bo->base.base.dev, 35 + struct panthor_device, base); 36 + 37 + if (list_empty(&bo->debugfs.node)) 38 + return; 39 + 40 + mutex_lock(&ptdev->gems.lock); 41 + list_del_init(&bo->debugfs.node); 42 + mutex_unlock(&ptdev->gems.lock); 43 + } 44 + 45 + #else 46 + static void panthor_gem_debugfs_bo_add(struct panthor_device *ptdev, 47 + struct panthor_gem_object *bo) 48 + {} 49 + static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {} 50 + #endif 16 51 17 52 static void panthor_gem_free_object(struct drm_gem_object *obj) 18 53 { 19 54 struct panthor_gem_object *bo = to_panthor_bo(obj); 20 55 struct drm_gem_object *vm_root_gem = bo->exclusive_vm_root_gem; 56 + 57 + panthor_gem_debugfs_bo_rm(bo); 21 58 22 59 /* 23 60 * Label might have been allocated with kstrdup_const(), ··· 125 88 struct drm_gem_shmem_object *obj; 126 89 struct panthor_kernel_bo *kbo; 127 90 struct panthor_gem_object *bo; 91 + u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL; 128 92 int ret; 129 93 130 94 if (drm_WARN_ON(&ptdev->base, !vm)) ··· 145 107 kbo->obj = &obj->base; 146 108 bo->flags = bo_flags; 147 109 110 + if (vm == panthor_fw_vm(ptdev)) 111 + debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED; 112 + 148 113 panthor_gem_kernel_bo_set_label(kbo, name); 114 + panthor_gem_debugfs_set_usage_flags(to_panthor_bo(kbo->obj), debug_flags); 149 115 150 116 /* The system and GPU MMU page size might differ, which becomes a 151 117 * problem for FW sections that need to be mapped at explicit address ··· 241 199 drm_gem_gpuva_set_lock(&obj->base.base, &obj->gpuva_list_lock); 242 200 mutex_init(&obj->label.lock); 243 201 202 + panthor_gem_debugfs_bo_add(ptdev, obj); 203 + 244 204 return &obj->base.base; 245 205 } 246 206 ··· 291 247 /* drop reference from allocate - handle holds it now. */ 292 248 drm_gem_object_put(&shmem->base); 293 249 250 + /* 251 + * No explicit flags are needed in the call below, since the 252 + * function internally sets the INITIALIZED bit for us. 253 + */ 254 + panthor_gem_debugfs_set_usage_flags(bo, 0); 255 + 294 256 return ret; 295 257 } 296 258 ··· 335 285 336 286 panthor_gem_bo_set_label(bo->obj, str); 337 287 } 288 + 289 + #ifdef CONFIG_DEBUG_FS 290 + struct gem_size_totals { 291 + size_t size; 292 + size_t resident; 293 + size_t reclaimable; 294 + }; 295 + 296 + static void panthor_gem_debugfs_print_flag_names(struct seq_file *m) 297 + { 298 + int len; 299 + int i; 300 + 301 + static const char * const gem_state_flags_names[] = { 302 + [PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported", 303 + [PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported", 304 + }; 305 + 306 + static const char * const gem_usage_flags_names[] = { 307 + [PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT] = "kernel", 308 + [PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT] = "fw-mapped", 309 + }; 310 + 311 + seq_puts(m, "GEM state flags: "); 312 + for (i = 0, len = ARRAY_SIZE(gem_state_flags_names); i < len; i++) { 313 + if (!gem_state_flags_names[i]) 314 + continue; 315 + seq_printf(m, "%s (0x%x)%s", gem_state_flags_names[i], 316 + (u32)BIT(i), (i < len - 1) ? ", " : "\n"); 317 + } 318 + 319 + seq_puts(m, "GEM usage flags: "); 320 + for (i = 0, len = ARRAY_SIZE(gem_usage_flags_names); i < len; i++) { 321 + if (!gem_usage_flags_names[i]) 322 + continue; 323 + seq_printf(m, "%s (0x%x)%s", gem_usage_flags_names[i], 324 + (u32)BIT(i), (i < len - 1) ? ", " : "\n\n"); 325 + } 326 + } 327 + 328 + static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo, 329 + struct seq_file *m, 330 + struct gem_size_totals *totals) 331 + { 332 + unsigned int refcount = kref_read(&bo->base.base.refcount); 333 + char creator_info[32] = {}; 334 + size_t resident_size; 335 + u32 gem_usage_flags = bo->debugfs.flags & (u32)~PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; 336 + u32 gem_state_flags = 0; 337 + 338 + /* Skip BOs being destroyed. */ 339 + if (!refcount) 340 + return; 341 + 342 + resident_size = bo->base.pages ? bo->base.base.size : 0; 343 + 344 + snprintf(creator_info, sizeof(creator_info), 345 + "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid); 346 + seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx", 347 + creator_info, 348 + bo->base.base.name, 349 + refcount, 350 + bo->base.base.size, 351 + resident_size, 352 + drm_vma_node_start(&bo->base.base.vma_node)); 353 + 354 + if (bo->base.base.import_attach) 355 + gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED; 356 + if (bo->base.base.dma_buf) 357 + gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED; 358 + 359 + seq_printf(m, "0x%-8x 0x%-10x", gem_state_flags, gem_usage_flags); 360 + 361 + scoped_guard(mutex, &bo->label.lock) { 362 + seq_printf(m, "%s\n", bo->label.str ? : ""); 363 + } 364 + 365 + totals->size += bo->base.base.size; 366 + totals->resident += resident_size; 367 + if (bo->base.madv > 0) 368 + totals->reclaimable += resident_size; 369 + } 370 + 371 + void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev, 372 + struct seq_file *m) 373 + { 374 + struct gem_size_totals totals = {0}; 375 + struct panthor_gem_object *bo; 376 + 377 + panthor_gem_debugfs_print_flag_names(m); 378 + 379 + seq_puts(m, "created-by global-name refcount size resident-size file-offset state usage label\n"); 380 + seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n"); 381 + 382 + scoped_guard(mutex, &ptdev->gems.lock) { 383 + list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) { 384 + if (bo->debugfs.flags & PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED) 385 + panthor_gem_debugfs_bo_print(bo, m, &totals); 386 + } 387 + } 388 + 389 + seq_puts(m, "==============================================================================================================================================\n"); 390 + seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n", 391 + totals.size, totals.resident, totals.reclaimable); 392 + } 393 + #endif
+65
drivers/gpu/drm/panthor/panthor_gem.h
··· 15 15 16 16 #define PANTHOR_BO_LABEL_MAXLEN 4096 17 17 18 + enum panthor_debugfs_gem_state_flags { 19 + PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT = 0, 20 + PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT = 1, 21 + 22 + /** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED: GEM BO is PRIME imported. */ 23 + PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT), 24 + 25 + /** @PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED: GEM BO is PRIME exported. */ 26 + PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED = BIT(PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT), 27 + }; 28 + 29 + enum panthor_debugfs_gem_usage_flags { 30 + PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT = 0, 31 + PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT = 1, 32 + 33 + /** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL: BO is for kernel use only. */ 34 + PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL = BIT(PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT), 35 + 36 + /** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED: BO is mapped on the FW VM. */ 37 + PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED = BIT(PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT), 38 + 39 + /** @PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED: BO is ready for DebugFS display. */ 40 + PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED = BIT(31), 41 + }; 42 + 43 + /** 44 + * struct panthor_gem_debugfs - GEM object's DebugFS list information 45 + */ 46 + struct panthor_gem_debugfs { 47 + /** 48 + * @node: Node used to insert the object in the device-wide list of 49 + * GEM objects, to display information about it through a DebugFS file. 50 + */ 51 + struct list_head node; 52 + 53 + /** @creator: Information about the UM process which created the GEM. */ 54 + struct { 55 + /** @creator.process_name: Group leader name in owning thread's process */ 56 + char process_name[TASK_COMM_LEN]; 57 + 58 + /** @creator.tgid: PID of the thread's group leader within its process */ 59 + pid_t tgid; 60 + } creator; 61 + 62 + /** @flags: Combination of panthor_debugfs_gem_usage_flags flags */ 63 + u32 flags; 64 + }; 65 + 18 66 /** 19 67 * struct panthor_gem_object - Driver specific GEM object. 20 68 */ ··· 110 62 /** @lock.str: Protects access to the @label.str field. */ 111 63 struct mutex lock; 112 64 } label; 65 + 66 + #ifdef CONFIG_DEBUG_FS 67 + struct panthor_gem_debugfs debugfs; 68 + #endif 113 69 }; 114 70 115 71 /** ··· 208 156 u64 gpu_va, const char *name); 209 157 210 158 void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo); 159 + 160 + #ifdef CONFIG_DEBUG_FS 161 + void panthor_gem_debugfs_print_bos(struct panthor_device *pfdev, 162 + struct seq_file *m); 163 + static inline void 164 + panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) 165 + { 166 + bo->debugfs.flags = usage_flags | PANTHOR_DEBUGFS_GEM_USAGE_FLAG_INITIALIZED; 167 + } 168 + 169 + #else 170 + void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}; 171 + #endif 211 172 212 173 #endif /* __PANTHOR_GEM_H__ */