From patchwork Sat Apr 9 20:31:21 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Widawsky X-Patchwork-Id: 696221 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 p39KX813029990 for ; Sat, 9 Apr 2011 20:33:28 GMT Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A5BFD9E782 for ; Sat, 9 Apr 2011 13:33:08 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from cloud01.chad-versace.us (184-106-247-128.static.cloud-ips.com [184.106.247.128]) by gabe.freedesktop.org (Postfix) with ESMTP id 17AE09EB16 for ; Sat, 9 Apr 2011 13:31:30 -0700 (PDT) Received: from localhost.localdomain (unknown [67.208.96.87]) by cloud01.chad-versace.us (Postfix) with ESMTPSA id B56C31D406B; Sat, 9 Apr 2011 20:32:21 +0000 (UTC) From: Ben Widawsky To: intel-gfx@lists.freedesktop.org Date: Sat, 9 Apr 2011 13:31:21 -0700 Message-Id: <1302381082-3167-4-git-send-email-ben@bwidawsk.net> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1302381082-3167-3-git-send-email-ben@bwidawsk.net> References: <1302284850-8274-1-git-send-email-ben@bwidawsk.net> <1302381082-3167-1-git-send-email-ben@bwidawsk.net> <1302381082-3167-2-git-send-email-ben@bwidawsk.net> <1302381082-3167-3-git-send-email-ben@bwidawsk.net> Subject: [Intel-gfx] [PATCH 3/4] drm/i915: userspace interface to the forcewake refcount 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.6 (demeter1.kernel.org [140.211.167.41]); Sat, 09 Apr 2011 20:33:28 +0000 (UTC) Provide debugfs access to the refcounted forcewake. This allows a userspace utility to access some of those hard to reach registers on newer GPUs. The interface is root-only. The interface is referred to as a forcewake lock. The term lock refers to the synchronization between software and hardware (powering down the GPU). A note for those not reading the comments in the patches: * "acquiring" the forcewake lock from userspace can fail. The utilities in userspace to read and write registers are inferior to the utilities in the kernel, and so failure (and inability to force acquire the lock) is acceptable. * "releasing" the forcewake lock can hang. The conditions under which this can happen are so severe it would almost certainly require a reboot anyway (i915 unload would also hang). Signed-off-by: Ben Widawsky --- drivers/gpu/drm/i915/i915_debugfs.c | 84 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_drv.c | 6 +++ 2 files changed, 90 insertions(+), 0 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 2edb8b2..dda687a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1192,6 +1192,17 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) return 0; } +static int i915_gen6_forcewake_count_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_i915_private *dev_priv = dev->dev_private; + + seq_printf(m, "forcewake count = %d\n", dev_priv->forcewake_count); + + return 0; +} + static int i915_wedged_open(struct inode *inode, struct file *filp) @@ -1294,6 +1305,72 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_wedged_fops); } +static int i915_forcewake_open(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (!IS_GEN6(dev)) + return 0; + + /* + * If the driver hangs while holding the lock, the user should turn on + * register read/write tracing, or use the other available debug options + * to to find the cause. + */ + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + gen6_gt_force_wake_get(dev_priv); + + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +int i915_forcewake_release(struct inode *inode, struct file *file) +{ + struct drm_device *dev = inode->i_private; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_GEN6(dev)) + return 0; + + /* + * If we hang, it implies that we have a locking issue, or some other + * oops in the driver. If we lock up userspace, that is an unfortunate + * but acceptable consequence. + */ + mutex_lock(&dev->struct_mutex); + gen6_gt_force_wake_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + +static const struct file_operations i915_forcewake_fops = { + .owner = THIS_MODULE, + .open = i915_forcewake_open, + .release = i915_forcewake_release, +}; + +static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_forcewake_lock", + S_IRWXU, + root, dev, + &i915_forcewake_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return 0; +} + static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -1330,6 +1407,7 @@ 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_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0}, }; #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list) @@ -1341,6 +1419,10 @@ int i915_debugfs_init(struct drm_minor *minor) if (ret) return ret; + ret = i915_forcewake_create(minor->debugfs_root, minor); + if (ret) + return ret; + return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor->debugfs_root, minor); @@ -1350,6 +1432,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) { drm_debugfs_remove_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops, + 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, 1, minor); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ce59cd4..96b3bfc 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -281,6 +281,12 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { + /* + * It takes a long time to wake, but the count is incremented + * immediately. Not having the lock causes a race, but all bets are off + * when using forced forcewake, which should only be touched through + * root-only entry in debugfs. + */ WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); if (dev_priv->forcewake_count++ == 0)