From patchwork Tue Nov 2 09:11:36 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yuanhan Liu X-Patchwork-Id: 296882 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oA29C3hi016404 for ; Tue, 2 Nov 2010 09:12:25 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 35F069E97E for ; Tue, 2 Nov 2010 02:12:03 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id 58BC49E82A for ; Tue, 2 Nov 2010 02:11:54 -0700 (PDT) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga101.fm.intel.com with ESMTP; 02 Nov 2010 02:11:54 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.58,281,1286175600"; d="scan'208";a="853280012" Received: from unknown (HELO localhost.localdomain.sh.intel.com) ([10.239.36.55]) by fmsmga001.fm.intel.com with ESMTP; 02 Nov 2010 02:11:53 -0700 From: Yuanhan Liu To: intel-gfx@lists.freedesktop.org Date: Tue, 2 Nov 2010 17:11:36 +0800 Message-Id: <1288689096-23230-1-git-send-email-yuanhan.liu@intel.com> X-Mailer: git-send-email 1.7.2.3 Subject: [Intel-gfx] [PATCH] drm/i915: Add aub debug support for kernel X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.11 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 02 Nov 2010 09:12:25 +0000 (UTC) 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 #include #include +#include #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, ®->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)