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

drm: add debugfs support on per client-id basis

add support to add a directory for each client-id
with root at the dri level. Since the clients are
unique and not just related to one single drm device,
so it makes more sense to add all the client based
nodes with root as dri.

Also create a debugfs file which show the process
information for the client and create a symlink back
to the parent drm device from each client.

Signed-off-by: Sunil Khatri <sunil.khatri@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Link: https://lore.kernel.org/r/20250704075548.1549849-3-sunil.khatri@amd.com
Signed-off-by: Christian König <christian.koenig@amd.com>

authored by

Sunil Khatri and committed by
Christian König
1fd45bc2 348fe34a

+110
+81
drivers/gpu/drm/drm_debugfs.c
··· 311 311 debugfs_remove(drm_debugfs_root); 312 312 } 313 313 314 + static int drm_debugfs_proc_info_show(struct seq_file *m, void *unused) 315 + { 316 + struct pid *pid; 317 + struct task_struct *task; 318 + struct drm_file *file = m->private; 319 + 320 + if (!file) 321 + return -EINVAL; 322 + 323 + rcu_read_lock(); 324 + pid = rcu_dereference(file->pid); 325 + task = pid_task(pid, PIDTYPE_TGID); 326 + 327 + seq_printf(m, "pid: %d\n", task ? task->pid : 0); 328 + seq_printf(m, "comm: %s\n", task ? task->comm : "Unset"); 329 + rcu_read_unlock(); 330 + return 0; 331 + } 332 + 333 + static int drm_debufs_proc_info_open(struct inode *inode, struct file *file) 334 + { 335 + return single_open(file, drm_debugfs_proc_info_show, inode->i_private); 336 + } 337 + 338 + static const struct file_operations drm_debugfs_proc_info_fops = { 339 + .owner = THIS_MODULE, 340 + .open = drm_debufs_proc_info_open, 341 + .read = seq_read, 342 + .llseek = seq_lseek, 343 + .release = single_release, 344 + }; 345 + 346 + /** 347 + * drm_debugfs_clients_add - Add a per client debugfs directory 348 + * @file: drm_file for a client 349 + * 350 + * Create the debugfs directory for each client. This will be used to populate 351 + * driver specific data for each client. 352 + * 353 + * Also add the process information debugfs file for each client to tag 354 + * which client belongs to which process. 355 + */ 356 + void drm_debugfs_clients_add(struct drm_file *file) 357 + { 358 + char *client; 359 + 360 + client = kasprintf(GFP_KERNEL, "client-%llu", file->client_id); 361 + if (!client) 362 + return; 363 + 364 + /* Create a debugfs directory for the client in root on drm debugfs */ 365 + file->debugfs_client = debugfs_create_dir(client, drm_debugfs_root); 366 + kfree(client); 367 + 368 + debugfs_create_file("proc_info", 0444, file->debugfs_client, file, 369 + &drm_debugfs_proc_info_fops); 370 + 371 + client = kasprintf(GFP_KERNEL, "../%s", file->minor->dev->unique); 372 + if (!client) 373 + return; 374 + 375 + /* Create a link from client_id to the drm device this client id belongs to */ 376 + debugfs_create_symlink("device", file->debugfs_client, client); 377 + kfree(client); 378 + } 379 + 380 + /** 381 + * drm_debugfs_clients_remove - removes all debugfs directories and files 382 + * @file: drm_file for a client 383 + * 384 + * Removes the debugfs directories recursively from the client directory. 385 + * 386 + * There is also a possibility that debugfs files are open while the drm_file 387 + * is released. 388 + */ 389 + void drm_debugfs_clients_remove(struct drm_file *file) 390 + { 391 + debugfs_remove_recursive(file->debugfs_client); 392 + file->debugfs_client = NULL; 393 + } 394 + 314 395 /** 315 396 * drm_debugfs_dev_init - create debugfs directory for the device 316 397 * @dev: the device which we want to create the directory for
+11
drivers/gpu/drm/drm_file.c
··· 46 46 #include <drm/drm_file.h> 47 47 #include <drm/drm_gem.h> 48 48 #include <drm/drm_print.h> 49 + #include <drm/drm_debugfs.h> 49 50 50 51 #include "drm_crtc_internal.h" 51 52 #include "drm_internal.h" ··· 169 168 170 169 drm_prime_init_file_private(&file->prime); 171 170 171 + if (!drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) 172 + drm_debugfs_clients_add(file); 173 + 172 174 if (dev->driver->open) { 173 175 ret = dev->driver->open(dev, file); 174 176 if (ret < 0) ··· 186 182 drm_syncobj_release(file); 187 183 if (drm_core_check_feature(dev, DRIVER_GEM)) 188 184 drm_gem_release(dev, file); 185 + 186 + if (!drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) 187 + drm_debugfs_clients_remove(file); 188 + 189 189 put_pid(rcu_access_pointer(file->pid)); 190 190 kfree(file); 191 191 ··· 243 235 current->comm, task_pid_nr(current), 244 236 (long)old_encode_dev(file->minor->kdev->devt), 245 237 atomic_read(&dev->open_count)); 238 + 239 + if (!drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) 240 + drm_debugfs_clients_remove(file); 246 241 247 242 drm_events_release(file); 248 243
+11
include/drm/drm_debugfs.h
··· 153 153 154 154 int drm_debugfs_gpuva_info(struct seq_file *m, 155 155 struct drm_gpuvm *gpuvm); 156 + 157 + void drm_debugfs_clients_add(struct drm_file *file); 158 + void drm_debugfs_clients_remove(struct drm_file *file); 156 159 #else 157 160 static inline void drm_debugfs_create_files(const struct drm_info_list *files, 158 161 int count, struct dentry *root, ··· 183 180 struct drm_gpuvm *gpuvm) 184 181 { 185 182 return 0; 183 + } 184 + 185 + static inline void drm_debugfs_clients_add(struct drm_file *file) 186 + { 187 + } 188 + 189 + static inline void drm_debugfs_clients_remove(struct drm_file *file) 190 + { 186 191 } 187 192 #endif 188 193
+7
include/drm/drm_file.h
··· 400 400 * @client_name_lock: Protects @client_name. 401 401 */ 402 402 struct mutex client_name_lock; 403 + 404 + /** 405 + * @debugfs_client: 406 + * 407 + * debugfs directory for each client under a drm node. 408 + */ 409 + struct dentry *debugfs_client; 403 410 }; 404 411 405 412 /**