@@ -1395,6 +1395,74 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
}
+static int i915_debugger_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 (atomic_add_return(1, &dev_priv->debug.debugging) != 1) {
+ atomic_dec(&dev_priv->debug.debugging);
+ return -EBUSY;
+ }
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret) {
+ atomic_dec(&dev_priv->debug.debugging);
+ return ret;
+ }
+
+ del_timer_sync(&dev_priv->hangcheck_timer);
+ dev_priv->hangcheck_disabled = true;
+
+ dev_priv->debug.debugger = current;
+
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
+
+static int i915_debugger_release(struct inode *inode, struct file *file)
+{
+ struct drm_device *dev = inode->i_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ mutex_lock(&dev->struct_mutex);
+
+ if (WARN_ON(dev_priv->debug.debugger != current))
+ return -ENXIO;
+
+ WARN_ON(atomic_dec_and_test(&dev_priv->debug.debugging) == 0);
+
+ dev_priv->debug.debugger = NULL;
+ dev_priv->hangcheck_disabled = false;
+ mutex_unlock(&dev->struct_mutex);
+ return 0;
+}
+
+static const struct file_operations i915_debugger_fops = {
+ .owner = THIS_MODULE,
+ .open = i915_debugger_open,
+ .release = i915_debugger_release,
+};
+
+static int i915_debugger_create(struct dentry *root, struct drm_minor *minor)
+{
+ struct drm_device *dev = minor->dev;
+ struct dentry *ent;
+
+ ent = debugfs_create_file("i915_debugger",
+ S_IRUSR,
+ root, dev,
+ &i915_debugger_fops);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+
+ return drm_add_fake_info_node(minor, ent, &i915_debugger_fops);
+
+ return 0;
+}
+
+
static struct drm_info_list i915_debugfs_list[] = {
{"i915_capabilities", i915_capabilities, 0},
{"i915_gem_objects", i915_gem_object_info, 0},
@@ -1448,6 +1516,9 @@ int i915_debugfs_init(struct drm_minor *minor)
if (ret)
return ret;
+ ret = i915_debugger_create(minor->debugfs_root, minor);
+ if (ret)
+ return ret;
return drm_debugfs_create_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
@@ -1457,6 +1528,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_debugger_fops,
+ 1, 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,
@@ -720,6 +720,12 @@ typedef struct drm_i915_private {
struct drm_property *force_audio_property;
atomic_t forcewake_count;
+
+ struct {
+ atomic_t debugging;
+ struct task_struct *debugger;
+ } debug;
+
} drm_i915_private_t;
enum i915_cache_level {
@@ -1723,7 +1723,7 @@ void i915_hangcheck_elapsed(unsigned long data)
}
repeat:
- BUG_ON(dev_priv->hangcheck_disabled);
+ WARN_ON(dev_priv->hangcheck_disabled);
/* Reset timer case chip hangs without another request being added */
mod_timer(&dev_priv->hangcheck_timer,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));