diff mbox

drm/i915: Add aub debug support for kernel

Message ID 1288689096-23230-1-git-send-email-yuanhan.liu@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Yuanhan Liu Nov. 2, 2010, 9:11 a.m. UTC
None
diff mbox

Patch

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)