[Intel-gfx] [PATCH] Add drm core debugfs implementation

Ben Gamari bgamari at gmail.com
Mon Jan 19 22:06:37 CET 2009


Many of the files currently in proc have no particular reason to be
there. This patch adds the infrastructure necessary to move these into
the debugfs filesystem
---
 drivers/gpu/drm/Makefile      |    2 +-
 drivers/gpu/drm/drm_debugfs.c |  214 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/drm_drv.c     |   10 ++
 drivers/gpu/drm/drm_info.c    |   60 ++++++++++++
 drivers/gpu/drm/drm_info.h    |    4 +
 drivers/gpu/drm/drm_stub.c    |   13 +++
 include/drm/drmP.h            |   38 +++++++
 7 files changed, 340 insertions(+), 1 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_debugfs.c

diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index ce9c765..4ec5061 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -11,7 +11,7 @@ drm-y       :=	drm_auth.o drm_bufs.o drm_cache.o \
 		drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
 		drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
 		drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \
-		drm_info.o
+		drm_info.o drm_debugfs.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
new file mode 100644
index 0000000..109936d
--- /dev/null
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -0,0 +1,214 @@
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "drm_info.h"
+
+#if defined(CONFIG_DEBUG_FS)
+
+/***************************************************
+ * Initialization, etc.
+ **************************************************/
+
+static struct drm_info_list drm_debugfs_list[] = {
+	{"name", drm_name_info, 0},
+	/*{"mem", drm_mem_info, 0},*/
+	{"vm", drm_vm_info, 0},
+	{"clients", drm_clients_info, 0},
+	{"queues", drm_queues_info, 0},
+	{"bufs", drm_bufs_info, 0},
+	{"gem_names", drm_gem_name_info, DRIVER_GEM},
+	{"gem_objects", drm_gem_object_info, DRIVER_GEM},
+#if DRM_DEBUG_CODE
+	{"vma", drm_vma_info, 0},
+#endif
+};
+#define DRM_DEBUGFS_ENTRIES ARRAY_SIZE(drm_debugfs_list)
+
+
+static int drm_debugfs_open(struct inode *inode, struct file *file)
+{
+	struct drm_info_node *node =
+	    (struct drm_info_node *) inode->i_private;
+
+	return single_open(file, node->info_ent->show, node);
+}
+
+
+static struct file_operations drm_debugfs_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_debugfs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+
+/**
+ * Initialize a given set of debugfs files for a device
+ *
+ * \param files The array of files to create
+ * \param count The number of files given
+ * \param root DRI debugfs dir entry.
+ * \param minor device minor number
+ * \return Zero on success, non-zero on failure
+ *
+ * Create a given set of debugfs files represented by an array of
+ * gdm_debugfs_lists in the given root directory.
+ */
+int drm_debugfs_create_files(struct drm_info_list *files, int count,
+			     struct dentry *root, struct drm_minor *minor)
+{
+	struct drm_device *dev = minor->dev;
+	struct dentry *ent;
+	struct drm_info_node *tmp;
+	char name[64];
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		u32 features = files[i].driver_features;
+
+		if (features != 0 &&
+		    (dev->driver->driver_features & features) != features)
+			continue;
+
+		tmp = (struct drm_info_node *)
+		    drm_alloc(sizeof(struct drm_info_node),
+			      _DRM_DRIVER);
+		ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
+					root, tmp, &drm_debugfs_fops);
+		if (!ent) {
+			DRM_ERROR("Cannot create /debugfs/dri/%s/%s\n",
+				  name, files[i].name);
+			drm_free(tmp, sizeof(struct drm_info_node),
+				 _DRM_DRIVER);
+			ret = -1;
+			goto fail;
+		}
+
+		tmp->minor = minor;
+		tmp->dent = ent;
+		tmp->info_ent = &files[i];
+		list_add(&(tmp->list), &(minor->debugfs_nodes.list));
+	}
+	return 0;
+
+      fail:
+	drm_debugfs_remove_files(files, count, minor);
+	return ret;
+}
+
+EXPORT_SYMBOL(drm_debugfs_create_files);
+
+/**
+ * Initialize the DRI debugfs filesystem for a device
+ *
+ * \param dev DRM device
+ * \param minor device minor number
+ * \param root DRI debugfs dir entry.
+ * \param dev_root resulting DRI device debugfs dir entry.
+ * \return root entry pointer on success, or NULL on failure.
+ *
+ * Create the DRI debugfs root entry "/debugfs/dri", the device debugfs root entry
+ * "/debugfs/dri/%minor%/", and each entry in debugfs_list as
+ * "/debugfs/dri/%minor%/%name%".
+ */
+int drm_debugfs_init(struct drm_minor *minor, int minor_id,
+		     struct dentry *root)
+{
+	struct drm_device *dev = minor->dev;
+	char name[64];
+	int ret;
+
+	INIT_LIST_HEAD(&minor->debugfs_nodes.list);
+	sprintf(name, "%d", minor_id);
+	minor->debugfs_root = debugfs_create_dir(name, root);
+	if (!minor->debugfs_root) {
+		DRM_ERROR("Cannot create /debugfs/dri/%s\n", name);
+		return -1;
+	}
+
+	ret =
+	    drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
+				     minor->debugfs_root, minor);
+	if (ret) {
+		debugfs_remove(minor->debugfs_root);
+		minor->debugfs_root = NULL;
+		DRM_ERROR("Failed to create core drm debugfs files\n");
+		return ret;
+	}
+
+	if (dev->driver->debugfs_init) {
+		ret = dev->driver->debugfs_init(minor);
+		if (ret) {
+			DRM_ERROR("DRM: Driver failed to initialize "
+				  "/debugfs/dri.\n");
+			return ret;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * Remove a list of debugfs files
+ *
+ * \param files The list of files
+ * \param count The number of files
+ * \param minor The minor of which we should remove the files
+ * \return always zero.
+ *
+ * Remove all debugfs entries created by debugfs_init().
+ */
+int drm_debugfs_remove_files(struct drm_info_list *files, int count,
+			     struct drm_minor *minor)
+{
+	struct list_head *pos, *q;
+	struct drm_info_node *tmp;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		list_for_each_safe(pos, q, &minor->debugfs_nodes.list) {
+			tmp = list_entry(pos, struct drm_info_node, list);
+			if (tmp->info_ent == &files[i]) {
+				debugfs_remove(tmp->dent);
+				list_del(pos);
+				drm_free(tmp,
+					 sizeof(struct drm_info_node),
+					 _DRM_DRIVER);
+			}
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(drm_debugfs_remove_files);
+
+/**
+ * Cleanup the debugfs filesystem resources.
+ *
+ * \param minor device minor number.
+ * \return always zero.
+ *
+ * Remove all debugfs entries created by debugfs_init().
+ */
+int drm_debugfs_cleanup(struct drm_minor *minor)
+{
+	struct drm_device *dev = minor->dev;
+
+	if (!minor->debugfs_root)
+		return 0;
+
+	if (dev->driver->debugfs_cleanup)
+		dev->driver->debugfs_cleanup(minor);
+
+	drm_debugfs_remove_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
+				 minor);
+
+	debugfs_remove(minor->debugfs_root);
+	minor->debugfs_root = NULL;
+
+	return 0;
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 5ff88d9..ba69383 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -46,9 +46,11 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/debugfs.h>
 #include "drmP.h"
 #include "drm_core.h"
 
+
 static int drm_version(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv);
 
@@ -378,6 +380,13 @@ static int __init drm_core_init(void)
 		goto err_p3;
 	}
 
+        drm_debugfs_root = debugfs_create_dir("dri", NULL);
+        if (!drm_debugfs_root) {
+                DRM_ERROR("Cannot create /debugfs/dri\n");
+                ret = -1;
+                goto err_p3;
+        }
+
 	drm_mem_init();
 
 	DRM_INFO("Initialized %s %d.%d.%d %s\n",
@@ -396,6 +405,7 @@ err_p1:
 static void __exit drm_core_exit(void)
 {
 	remove_proc_entry("dri", NULL);
+	debugfs_remove(drm_debugfs_root);
 	drm_sysfs_destroy();
 
 	unregister_chrdev(DRM_MAJOR, "drm");
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 555f6fd..02882f0 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -290,3 +290,63 @@ int drm_gem_object_info(struct seq_file *m, void* data)
 	return 0;
 }
 
+#if DRM_DEBUG_CODE
+
+static int drm__vma_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_vma_entry *pt;
+	struct vm_area_struct *vma;
+#if defined(__i386__)
+	unsigned int pgprot;
+#endif
+
+	seq_printf(m, "vma use count: %d, high_memory = %p, 0x%08lx\n",
+		   atomic_read(&dev->vma_count),
+		   high_memory, virt_to_phys(high_memory));
+	list_for_each_entry(pt, &dev->vmalist, head) {
+		if (!(vma = pt->vma))
+			continue;
+		seq_printf(m,
+			   "\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
+			   pt->pid, vma->vm_start, vma->vm_end,
+			   vma->vm_flags & VM_READ ? 'r' : '-',
+			   vma->vm_flags & VM_WRITE ? 'w' : '-',
+			   vma->vm_flags & VM_EXEC ? 'x' : '-',
+			   vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
+			   vma->vm_flags & VM_LOCKED ? 'l' : '-',
+			   vma->vm_flags & VM_IO ? 'i' : '-',
+			   vma->vm_pgoff);
+
+#if defined(__i386__)
+		pgprot = pgprot_val(vma->vm_page_prot);
+		seq_printf(m, " %c%c%c%c%c%c%c%c%c",
+			   pgprot & _PAGE_PRESENT ? 'p' : '-',
+			   pgprot & _PAGE_RW ? 'w' : 'r',
+			   pgprot & _PAGE_USER ? 'u' : 's',
+			   pgprot & _PAGE_PWT ? 't' : 'b',
+			   pgprot & _PAGE_PCD ? 'u' : 'c',
+			   pgprot & _PAGE_ACCESSED ? 'a' : '-',
+			   pgprot & _PAGE_DIRTY ? 'd' : '-',
+			   pgprot & _PAGE_PSE ? 'm' : 'k',
+			   pgprot & _PAGE_GLOBAL ? 'g' : 'l');
+#endif
+		seq_printf(m, "\n");
+	}
+	return 0;
+}
+
+int drm_vma_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	int ret;
+
+	mutex_lock(&dev->struct_mutex);
+	ret = drm__vma_info(m, data);
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+#endif
+
diff --git a/drivers/gpu/drm/drm_info.h b/drivers/gpu/drm/drm_info.h
index 63adbe7..c123291 100644
--- a/drivers/gpu/drm/drm_info.h
+++ b/drivers/gpu/drm/drm_info.h
@@ -7,3 +7,7 @@ int drm_clients_info(struct seq_file *m, void* data);
 int drm_gem_name_info(struct seq_file *m, void *data);
 int drm_gem_object_info(struct seq_file *m, void* data);
 
+#if DRM_DEBUG_CODE
+int drm_vma_info(struct seq_file *m, void *data);
+#endif
+
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 566847d..77eb36b 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -50,6 +50,7 @@ struct idr drm_minors_idr;
 
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
+struct dentry *drm_debugfs_root;
 
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
@@ -315,6 +316,14 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
 	} else
 		new_minor->proc_root = NULL;
 
+#if defined(CONFIG_DEBUG_FS)
+        ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
+        if (ret) {
+                DRM_ERROR("DRM: Failed to initialize /debugfs/dri.\n");
+                goto err_g2;
+        }
+#endif
+
 	ret = drm_sysfs_device_add(new_minor);
 	if (ret) {
 		printk(KERN_ERR
@@ -451,6 +460,10 @@ int drm_put_minor(struct drm_minor **minor_p)
 
 	if (minor->type == DRM_MINOR_LEGACY)
 		drm_proc_cleanup(minor, drm_proc_root);
+#if defined(CONFIG_DEBUG_FS)
+	drm_debugfs_cleanup(minor);
+#endif
+
 	drm_sysfs_device_remove(minor);
 
 	idr_remove(&drm_minors_idr, minor->index);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 7461ae7..9a80f01 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -765,6 +765,8 @@ struct drm_driver {
 
 	int (*proc_init)(struct drm_minor *minor);
 	void (*proc_cleanup)(struct drm_minor *minor);
+	int (*debugfs_init)(struct drm_minor *minor);
+	void (*debugfs_cleanup)(struct drm_minor *minor);
 
 	/**
 	 * Driver-specific constructor for drm_gem_objects, to set up
@@ -800,6 +802,27 @@ struct drm_driver {
 #define DRM_MINOR_CONTROL 2
 #define DRM_MINOR_RENDER 3
 
+
+/**
+ * debugfs node list. This structure represents a debugfs file to
+ * be created by the drm core
+ */
+struct drm_debugfs_list {
+	const char *name; /** file name */
+	int (*show)(struct seq_file*, void*); /** show callback */
+	u32 driver_features; /**< Required driver features for this entry */
+};
+
+/**
+ * debugfs node structure. This structure represents a debugfs file.
+ */
+struct drm_debugfs_node {
+	struct list_head list;
+	struct drm_minor *minor;
+	struct drm_debugfs_list *debugfs_ent;
+	struct dentry *dent;  
+};
+
 /**
  * Info file list entry. This structure represents a debugfs or proc file to
  * be created by the drm core
@@ -833,6 +856,8 @@ struct drm_minor {
 
 	struct proc_dir_entry *proc_root;  /**< proc directory entry */
 	struct drm_info_node proc_nodes;
+	struct dentry *debugfs_root;
+	struct drm_info_node debugfs_nodes;
 
 	struct drm_master *master; /* currently active master for this node */
 	struct list_head master_list;
@@ -1291,6 +1316,7 @@ extern unsigned int drm_debug;
 
 extern struct class *drm_class;
 extern struct proc_dir_entry *drm_proc_root;
+extern struct dentry *drm_debugfs_root;
 
 extern struct idr drm_minors_idr;
 
@@ -1301,6 +1327,18 @@ extern int drm_proc_init(struct drm_minor *minor, int minor_id,
 			 struct proc_dir_entry *root);
 extern int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root);
 
+                                /* Debugfs support */
+#if defined(CONFIG_DEBUG_FS)
+extern int drm_debugfs_init(struct drm_minor *minor, int minor_id,
+                            struct dentry *root);
+extern int drm_debugfs_create_files(struct drm_info_list *files, int count,
+                                    struct dentry *root,
+                                    struct drm_minor *minor);
+extern int drm_debugfs_remove_files(struct drm_info_list *files, int count,
+                                    struct drm_minor *minor);
+extern int drm_debugfs_cleanup(struct drm_minor *minor);
+#endif
+
 				/* Scatter Gather Support (drm_scatter.h) */
 extern void drm_sg_cleanup(struct drm_sg_mem * entry);
 extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
-- 
1.6.0.6




More information about the Intel-gfx mailing list