[Intel-gfx] [PATCH] drm/i915: Add aub debug support for kernel

Yuanhan Liu yuanhan.liu at intel.com
Tue Nov 2 10:11:36 CET 2010


The AUB file is a file format used by Intel's internal simulation
and other validation tools. The content of an aub file is a subset
collection of all the data needed by GPU.

Here now just collects the data that are going to be written into
register, since the others data like ring buffer, buffer objects
are dumped at user space by libdrm.

The currentl implementation: hooks the I915_WRITEx macro. The basic
idea is write down all the reg offset and reg val before writing
them to register.

Since it's a debug feature, it's disabled by default. You can add
the following line into kernel cmdline in your bootloader's config
file to enable it:

i915.aub_debug=1

This comes two files under ${debugfs_mntpoint}/dri/0/ named:
i915.aub	-- the aub file
i915_aub_reset  -- read this file to reset the aub data buffer, as
		   the size of aub data buffer is so limite, while
		   the aub data is so huge. Well, I'm not sure I
		   should add this debug file.

comments?

Signed-off-by: Yuanhan Liu <yuanhan.liu at intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c |  173 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_drv.c     |    3 +
 drivers/gpu/drm/i915/i915_drv.h     |   76 +++++++++++++++-
 3 files changed, 249 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 1f4f3ce..b953547 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -29,6 +29,7 @@
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include "drmP.h"
 #include "drm.h"
 #include "intel_drv.h"
@@ -1015,6 +1016,165 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
 	return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
 }
 
+static void * i915_aub_data = NULL;
+static struct i915_aub_data * i915_aub_data_ptr = NULL;
+static struct mutex i915_aub_data_lock;
+
+static inline void i915_aub_out(struct seq_file *m, uint32_t data)
+{
+	seq_write(m, &data, 4);
+}
+
+static inline void 
+i915_aub_out_data(struct seq_file *m, void *data, size_t size)
+{
+	seq_write(m, data, size);
+}
+
+
+/*
+ * Check should we trace this register. Since some registers, 
+ * like GPIOX,  writes too often, which will fill up the 
+ * i915_aub_data buffer soon. That's really not good!
+ *
+ * You can add your own filter here.
+ */
+static int i915_aub_trace_reg(uint32_t reg)
+{
+#if 0
+	if ((reg - PCH_GPIOA) >= 0 && 
+	    (reg - PCH_GPIOA) <= (PCH_GPIOF - PCH_GPIOA))
+		return 0;
+	if (reg == CURABASE || reg == CURAPOS ||
+	    reg == CURBBASE || reg == CURBPOS)
+		return 0;
+#endif
+	return 1;
+}
+
+void i915_aub_write_reg(uint32_t reg, uint64_t val, int len)
+{
+	if (!i915_aub_trace_reg(reg))
+		return;
+	
+	mutex_lock(&i915_aub_data_lock);
+	if ((void *)i915_aub_data_ptr < i915_aub_data + AUB_DATA_SIZE) {
+		i915_aub_data_ptr->type = AUB_TYPE_REG;
+		i915_aub_data_ptr->size = len;
+		i915_aub_data_ptr->addr = reg;
+		i915_aub_data_ptr->data  = val;
+		i915_aub_data_ptr++;
+	}
+	mutex_unlock(&i915_aub_data_lock);
+}
+
+
+/*
+ * Write out the aub header
+ */
+static void i915_aub_out_header(struct seq_file *m)
+{
+	char app_name[AUB_APP_NAME_LEN] = "kernel-i915";
+
+	i915_aub_out(m, AUB_CMD_HEADER | (13 - 2));
+	i915_aub_out(m, AUB_VERSION);
+	i915_aub_out_data(m, app_name, AUB_APP_NAME_LEN);
+	i915_aub_out(m, 0); /* timestamp */
+	i915_aub_out(m, 0); /* timestamp */
+	i915_aub_out(m, 0); /* comment len */
+}
+
+static void i915_aub_out_reg(struct seq_file *m, struct i915_aub_data *reg)
+{
+	i915_aub_out(m, AUB_CMD_TRACE_HEADER_BLOCK | (5 - 2));
+	i915_aub_out(m, AUB_TRACE_OP_MMIO_WRITE);
+	i915_aub_out(m, 0);
+	i915_aub_out(m, reg->addr); /* reg offset */
+	i915_aub_out(m, reg->size); /* size */
+	i915_aub_out_data(m, &reg->data, reg->size); /* data */
+}
+
+/* 
+ * Set up the GTT. The max we can handle is 256M 
+ *
+ * FIXME: is 256M OK?
+ */
+static void i915_aub_setup_gtt(struct seq_file *m)
+{
+	int i;
+	uint32_t entry = 0x200003;
+
+	for (i = 0x0; i < 0x10000; i += 4, entry += 0x1000) {
+		i915_aub_out(m, AUB_CMD_TRACE_HEADER_BLOCK | (5 - 2));
+		i915_aub_out(m, AUB_TRACE_MEMTYPE_NONLOCAL | 0 | AUB_TRACE_OP_DATA_WRITE);
+		i915_aub_out(m, 0);
+		i915_aub_out(m, i);
+		i915_aub_out(m, 4);
+		i915_aub_out(m, entry);
+	}
+}
+
+/*
+ * It's time to tell fulsim to handle these data
+ */
+static void i915_aub_draw(struct seq_file *m)
+{
+	/*  AUB_CMD_DRAW */
+	i915_aub_out(m, AUB_CMD_DRAW | 5);
+	
+	/* FIXME: currently write all ZERO */
+	i915_aub_out(m, 0x0); /* Lenght */
+	i915_aub_out(m, 0x0); /* Flags */
+	i915_aub_out(m, 0x0); /* XLeft, Ytop */
+	i915_aub_out(m, 0x0); /* Width, Height */
+	i915_aub_out(m, 0x0); /* BitsPerPixels,  Pitch */
+	i915_aub_out(m, 0x0); /* SpanGrid */
+}
+
+static int i915_aub(struct seq_file *m, void *unused)
+{
+	struct i915_aub_data *p = (struct i915_aub_data *)i915_aub_data;
+	struct i915_aub_data *end = i915_aub_data_ptr;
+
+	if (i915_aub_debug == 0) {
+		seq_printf(m, "aub debug is disabled! You can add 'i915.aub_debug=1' "
+			   "at the end of boot command line to enable it.\n");
+		return 0;
+	}
+	
+	i915_aub_out_header(m);
+
+	if ((void *)i915_aub_data_ptr >= i915_aub_data + AUB_DATA_SIZE)
+		printk("WARNING: i915_aub_data_ptr exceed the size of aub data"
+		       " buffer. You may want to enlarge the size\n");
+
+	/* FIXME: As we are now in kernel, should we do thing? */
+	i915_aub_setup_gtt(m);
+
+	while (p < end) {
+		if (p->type == AUB_TYPE_REG)
+			i915_aub_out_reg(m, p);
+		else
+			DRM_ERROR("Invaled aub type(%d)\n", p->type);
+
+		p++;
+	}
+
+	i915_aub_draw(m);
+
+	return 0;
+}
+
+static int i915_aub_reset(struct seq_file *m, void *unused)
+{
+	if (i915_aub_debug) {
+		mutex_lock(&i915_aub_data_lock);
+		i915_aub_data_ptr = (struct i915_aub_data *)i915_aub_data;
+		mutex_unlock(&i915_aub_data_lock);
+	}
+	return 0;
+}
+
 static struct drm_info_list i915_debugfs_list[] = {
 	{"i915_capabilities", i915_capabilities, 0, 0},
 	{"i915_gem_objects", i915_gem_object_info, 0},
@@ -1044,6 +1204,8 @@ static struct drm_info_list i915_debugfs_list[] = {
 	{"i915_sr_status", i915_sr_status, 0},
 	{"i915_opregion", i915_opregion, 0},
 	{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
+	{"i915.aub", i915_aub, 0},
+	{"i915_aub_reset", i915_aub_reset, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -1055,6 +1217,14 @@ int i915_debugfs_init(struct drm_minor *minor)
 	if (ret)
 		return ret;
 
+	if (i915_aub_debug) {
+		i915_aub_data = vmalloc(AUB_DATA_SIZE);
+		if (!i915_aub_data)
+			return -ENOMEM;
+		i915_aub_data_ptr = (struct i915_aub_data *)i915_aub_data;
+		mutex_init(&i915_aub_data_lock);
+	}
+
 	return drm_debugfs_create_files(i915_debugfs_list,
 					I915_DEBUGFS_ENTRIES,
 					minor->debugfs_root, minor);
@@ -1066,6 +1236,9 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
 				 I915_DEBUGFS_ENTRIES, minor);
 	drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
 				 1, minor);
+
+	if (i915_aub_debug)
+		vfree(i915_aub_data);
 }
 
 #endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 3467dd4..9b6589c 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -40,6 +40,9 @@
 static int i915_modeset = -1;
 module_param_named(modeset, i915_modeset, int, 0400);
 
+int i915_aub_debug = 0;
+module_param_named(aub_debug, i915_aub_debug, int, 0400);
+
 unsigned int i915_fbpercrtc = 0;
 module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2c2c19b..3c8f4b4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -880,6 +880,50 @@ enum intel_chip_family {
 	CHIP_I965 = 0x08,
 };
 
+#define AUB_CMD				(7 << 29)
+#define AUB_APP_NAME_LEN		32
+
+/*
+ * 32 Page is really not enough. Since some registers, like CURAPOS and
+ * CURABASE will fill up the aub data buffer soon!
+ *
+ * So, if you want to record everything(impossible, in fact)!, change 
+ * the size here.
+ */
+#define AUB_DATA_SIZE 			(32 << PAGE_SHIFT)
+
+#define AUB_HEADER_MAJOR_SHIFT		24
+#define AUB_HEADER_MINOR_SHIFT		16
+#define AUB_VERSION 			((4 << AUB_HEADER_MAJOR_SHIFT) | \
+			 		 (0 << AUB_HEADER_MINOR_SHIFT))
+
+#define AUB_CMD_HEADER			(AUB_CMD | (1 << 23) | (0x05 << 16))
+#define AUB_CMD_TRACE_HEADER_BLOCK	(AUB_CMD | (1 << 23) | (0x41 << 16))
+#define AUB_CMD_DRAW               	(AUB_CMD | (1 << 23) | (0xaf << 16))
+
+
+#define AUB_TRACE_MEMTYPE_GTT		(0 << 16)
+#define AUB_TRACE_MEMTYPE_LOCAL		(1 << 16)
+#define AUB_TRACE_MEMTYPE_NONLOCAL	(2 << 16)
+
+#define AUB_TRACE_OP_DATA_WRITE		0x00000001
+#define AUB_TRACE_OP_MMIO_WRITE		0x00000003
+
+struct i915_aub_data {
+	uint32_t type:8;
+	uint32_t size:24;
+	uint32_t addr;
+	uint64_t data;
+};
+
+/* Currently support one type of data */
+enum i915_aub_type {
+	AUB_TYPE_REG = 1,
+};
+
+
+extern int i915_aub_debug;
+
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 extern unsigned int i915_fbpercrtc;
@@ -1105,6 +1149,7 @@ void i915_gem_dump_object(struct drm_gem_object *obj, int len,
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
 void i915_debugfs_cleanup(struct drm_minor *minor);
+void i915_aub_write_reg(uint32_t reg, uint64_t val, int len);
 
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
@@ -1195,18 +1240,43 @@ static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
 static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
 			      u32 val)
 {
+	if (i915_aub_debug)
+		i915_aub_write_reg(reg, val, 4);
 	writel(val, dev_priv->regs + reg);
 	if (dev_priv->debug_flags & I915_DEBUG_WRITE)
 		printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
 }
 
+static inline void i915_writeb(struct drm_i915_private *dev_priv, u32 reg,
+			      u8 val)
+{
+	if (i915_aub_debug)
+		i915_aub_write_reg(reg, val, 1);
+	writeb(val, dev_priv->regs + reg);
+}
+
+static inline void i915_writew(struct drm_i915_private *dev_priv, u32 reg,
+			      u16 val)
+{
+	if (i915_aub_debug)
+		i915_aub_write_reg(reg, val, 2);
+	writew(val, dev_priv->regs + reg);
+}
+
+static inline void i915_writeq(struct drm_i915_private *dev_priv, u32 reg,
+			      u64 val)
+{
+	if (i915_aub_debug)
+		i915_aub_write_reg(reg, val, 8);
+	writeq(val, dev_priv->regs + reg);
+}
 #define I915_READ(reg)          i915_read(dev_priv, (reg))
 #define I915_WRITE(reg, val)    i915_write(dev_priv, (reg), (val))
 #define I915_READ16(reg)	readw(dev_priv->regs + (reg))
-#define I915_WRITE16(reg, val)	writel(val, dev_priv->regs + (reg))
+#define I915_WRITE16(reg, val)	i915_writew(dev_priv, (reg), (val))
 #define I915_READ8(reg)		readb(dev_priv->regs + (reg))
-#define I915_WRITE8(reg, val)	writeb(val, dev_priv->regs + (reg))
-#define I915_WRITE64(reg, val)	writeq(val, dev_priv->regs + (reg))
+#define I915_WRITE8(reg, val)	i915_writeb(dev_priv, (reg), (val))
+#define I915_WRITE64(reg, val)	i915_writeq(dev_priv, (reg), (val))
 #define I915_READ64(reg)	readq(dev_priv->regs + (reg))
 #define POSTING_READ(reg)	(void)I915_READ(reg)
 #define POSTING_READ16(reg)	(void)I915_READ16(reg)
-- 
1.7.0.1




More information about the Intel-gfx mailing list