diff options
Diffstat (limited to 'drivers/gpu/drm/drm_debugfs.c')
-rw-r--r-- | drivers/gpu/drm/drm_debugfs.c | 166 |
1 files changed, 119 insertions, 47 deletions
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 6b2178864c7e..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 */ @@ -740,40 +848,6 @@ void drm_debugfs_crtc_remove(struct drm_crtc *crtc) crtc->debugfs_entry = NULL; } -static int bridges_show(struct seq_file *m, void *data) -{ - struct drm_encoder *encoder = m->private; - struct drm_printer p = drm_seq_file_printer(m); - struct drm_bridge *bridge; - unsigned int idx = 0; - - drm_for_each_bridge_in_chain(encoder, bridge) { - drm_printf(&p, "bridge[%u]: %ps\n", idx++, bridge->funcs); - drm_printf(&p, "\ttype: [%d] %s\n", - bridge->type, - drm_get_connector_type_name(bridge->type)); - - if (bridge->of_node) - drm_printf(&p, "\tOF: %pOFfc\n", bridge->of_node); - - drm_printf(&p, "\tops: [0x%x]", bridge->ops); - if (bridge->ops & DRM_BRIDGE_OP_DETECT) - drm_puts(&p, " detect"); - if (bridge->ops & DRM_BRIDGE_OP_EDID) - drm_puts(&p, " edid"); - if (bridge->ops & DRM_BRIDGE_OP_HPD) - drm_puts(&p, " hpd"); - if (bridge->ops & DRM_BRIDGE_OP_MODES) - drm_puts(&p, " modes"); - if (bridge->ops & DRM_BRIDGE_OP_HDMI) - drm_puts(&p, " hdmi"); - drm_puts(&p, "\n"); - } - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(bridges); - void drm_debugfs_encoder_add(struct drm_encoder *encoder) { struct drm_minor *minor = encoder->dev->primary; @@ -789,9 +863,7 @@ void drm_debugfs_encoder_add(struct drm_encoder *encoder) encoder->debugfs_entry = root; - /* bridges list */ - debugfs_create_file("bridges", 0444, root, encoder, - &bridges_fops); + drm_bridge_debugfs_encoder_params(root, encoder); if (encoder->funcs && encoder->funcs->debugfs_init) encoder->funcs->debugfs_init(encoder, root); |