diff options
Diffstat (limited to 'drivers/gpu/drm/drm_debugfs.c')
| -rw-r--r-- | drivers/gpu/drm/drm_debugfs.c | 128 | 
1 files changed, 118 insertions, 10 deletions
| diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 3dfd8b34dceb..365cf337529f 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -44,6 +44,9 @@  #include "drm_crtc_internal.h"  #include "drm_internal.h" +static struct dentry *accel_debugfs_root; +static struct dentry *drm_debugfs_root; +  /***************************************************   * Initialization, etc.   **************************************************/ @@ -77,14 +80,15 @@ static int drm_clients_info(struct seq_file *m, void *data)  	kuid_t uid;  	seq_printf(m, -		   "%20s %5s %3s master a %5s %10s %*s\n", +		   "%20s %5s %3s master a %5s %10s %*s %20s\n",  		   "command",  		   "tgid",  		   "dev",  		   "uid",  		   "magic",  		   DRM_CLIENT_NAME_MAX_LEN, -		   "name"); +		   "name", +		   "id");  	/* dev->filelist is sorted youngest first, but we want to present  	 * oldest first (i.e. kernel, servers, clients), so walk backwardss. @@ -100,7 +104,7 @@ static int drm_clients_info(struct seq_file *m, void *data)  		pid = rcu_dereference(priv->pid);  		task = pid_task(pid, PIDTYPE_TGID);  		uid = task ? __task_cred(task)->euid : GLOBAL_ROOT_UID; -		seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u %*s\n", +		seq_printf(m, "%20s %5d %3d   %c    %c %5d %10u %*s %20llu\n",  			   task ? task->comm : "<unknown>",  			   pid_vnr(pid),  			   priv->minor->index, @@ -109,7 +113,8 @@ static int drm_clients_info(struct seq_file *m, void *data)  			   from_kuid_munged(seq_user_ns(m), uid),  			   priv->magic,  			   DRM_CLIENT_NAME_MAX_LEN, -			   priv->client_name ? priv->client_name : "<unset>"); +			   priv->client_name ? priv->client_name : "<unset>", +			   priv->client_id);  		rcu_read_unlock();  		mutex_unlock(&priv->client_name_lock);  	} @@ -285,16 +290,120 @@ int drm_debugfs_remove_files(const struct drm_info_list *files, int count,  }  EXPORT_SYMBOL(drm_debugfs_remove_files); +void drm_debugfs_bridge_params(void) +{ +	drm_bridge_debugfs_params(drm_debugfs_root); +} + +void drm_debugfs_init_root(void) +{ +	drm_debugfs_root = debugfs_create_dir("dri", NULL); +#if IS_ENABLED(CONFIG_DRM_ACCEL) +	accel_debugfs_root = debugfs_create_dir("accel", NULL); +#endif +} + +void drm_debugfs_remove_root(void) +{ +#if IS_ENABLED(CONFIG_DRM_ACCEL) +	debugfs_remove(accel_debugfs_root); +#endif +	debugfs_remove(drm_debugfs_root); +} + +static int drm_debugfs_proc_info_show(struct seq_file *m, void *unused) +{ +	struct pid *pid; +	struct task_struct *task; +	struct drm_file *file = m->private; + +	if (!file) +		return -EINVAL; + +	rcu_read_lock(); +	pid = rcu_dereference(file->pid); +	task = pid_task(pid, PIDTYPE_TGID); + +	seq_printf(m, "pid: %d\n", task ? task->pid : 0); +	seq_printf(m, "comm: %s\n", task ? task->comm : "Unset"); +	rcu_read_unlock(); +	return 0; +} + +static int drm_debufs_proc_info_open(struct inode *inode, struct file *file) +{ +	return single_open(file, drm_debugfs_proc_info_show, inode->i_private); +} + +static const struct file_operations drm_debugfs_proc_info_fops = { +	.owner = THIS_MODULE, +	.open = drm_debufs_proc_info_open, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; + +/** + * drm_debugfs_clients_add - Add a per client debugfs directory + * @file: drm_file for a client + * + * Create the debugfs directory for each client. This will be used to populate + * driver specific data for each client. + * + * Also add the process information debugfs file for each client to tag + * which client belongs to which process. + */ +void drm_debugfs_clients_add(struct drm_file *file) +{ +	char *client; + +	client = kasprintf(GFP_KERNEL, "client-%llu", file->client_id); +	if (!client) +		return; + +	/* Create a debugfs directory for the client in root on drm debugfs */ +	file->debugfs_client = debugfs_create_dir(client, drm_debugfs_root); +	kfree(client); + +	debugfs_create_file("proc_info", 0444, file->debugfs_client, file, +			    &drm_debugfs_proc_info_fops); + +	client = kasprintf(GFP_KERNEL, "../%s", file->minor->dev->unique); +	if (!client) +		return; + +	/* Create a link from client_id to the drm device this client id belongs to */ +	debugfs_create_symlink("device", file->debugfs_client, client); +	kfree(client); +} + +/** + * drm_debugfs_clients_remove - removes all debugfs directories and files + * @file: drm_file for a client + * + * Removes the debugfs directories recursively from the client directory. + * + * There is also a possibility that debugfs files are open while the drm_file + * is released. + */ +void drm_debugfs_clients_remove(struct drm_file *file) +{ +	debugfs_remove_recursive(file->debugfs_client); +	file->debugfs_client = NULL; +} +  /**   * drm_debugfs_dev_init - create debugfs directory for the device   * @dev: the device which we want to create the directory for - * @root: the parent directory depending on the device type   *   * Creates the debugfs directory for the device under the given root directory.   */ -void drm_debugfs_dev_init(struct drm_device *dev, struct dentry *root) +void drm_debugfs_dev_init(struct drm_device *dev)  { -	dev->debugfs_root = debugfs_create_dir(dev->unique, root); +	if (drm_core_check_feature(dev, DRIVER_COMPUTE_ACCEL)) +		dev->debugfs_root = debugfs_create_dir(dev->unique, accel_debugfs_root); +	else +		dev->debugfs_root = debugfs_create_dir(dev->unique, drm_debugfs_root);  }  /** @@ -321,14 +430,13 @@ void drm_debugfs_dev_register(struct drm_device *dev)  		drm_atomic_debugfs_init(dev);  } -int drm_debugfs_register(struct drm_minor *minor, int minor_id, -			 struct dentry *root) +int drm_debugfs_register(struct drm_minor *minor, int minor_id)  {  	struct drm_device *dev = minor->dev;  	char name[64];  	sprintf(name, "%d", minor_id); -	minor->debugfs_symlink = debugfs_create_symlink(name, root, +	minor->debugfs_symlink = debugfs_create_symlink(name, drm_debugfs_root,  							dev->unique);  	/* TODO: Only for compatibility with drivers */ | 
