Provide a user accessible way to change the hangcheck timer. This is
useful mostly for disabling the timer completely (value <= 0).

Signed-off-by: Ben Widawsky <b...@bwidawsk.net>
Cc: Keith Packard <kei...@keithp.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c |   88 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_dma.c     |    1 +
 drivers/gpu/drm/i915/i915_drv.h     |    1 +
 drivers/gpu/drm/i915/i915_gem.c     |    7 ++-
 drivers/gpu/drm/i915/i915_irq.c     |   17 +++++--
 5 files changed, 107 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
b/drivers/gpu/drm/i915/i915_debugfs.c
index 4d46441..b6582de 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1395,6 +1395,88 @@ 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_hangcheck_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t i915_hangcheck_read(struct file *filp,
+                                  char __user *ubuf,
+                                  size_t max,
+                                  loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       char buf[7];
+       int len, timeout;
+
+       timeout = atomic_read(&dev_priv->hangcheck_timeout);
+       len = snprintf(buf, sizeof(buf), "%d\n", timeout);
+
+       return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+}
+
+static ssize_t i915_hangcheck_write(struct file *filp,
+                                   const char __user *ubuf,
+                                   size_t cnt,
+                                   loff_t *ppos)
+{
+       struct drm_device *dev = filp->private_data;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       char buf[7]; /* 99.9 seconds max */
+       int new_timeout = 0;
+       int ret;
+
+       if (cnt > 0) {
+               if (cnt > sizeof (buf) - 1)
+                       return -EINVAL;
+
+               if (copy_from_user(buf, ubuf, cnt))
+                       return -EFAULT;
+               buf[cnt] = 0;
+
+               new_timeout = simple_strtol(buf, NULL, 0);
+       }
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       if (new_timeout <= 0) {
+               new_timeout = 0;
+               del_timer_sync(&dev_priv->hangcheck_timer);
+       }
+
+       atomic_set(&dev_priv->hangcheck_timeout, new_timeout);
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return cnt;
+}
+
+static const struct file_operations i915_hangcheck_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_hangcheck_open,
+       .read = i915_hangcheck_read,
+       .write = i915_hangcheck_write,
+};
+
+static int i915_hangcheck_create(struct dentry *root, struct drm_minor *minor)
+{
+       struct drm_device *dev = minor->dev;
+       struct dentry *ent;
+
+       ent = debugfs_create_file("i915_hangcheck_timeout",
+                                 S_IRUGO | S_IWUSR,
+                                 root, dev,
+                                 &i915_hangcheck_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       return drm_add_fake_info_node(minor, ent, &i915_hangcheck_fops);
+}
+
 static struct drm_info_list i915_debugfs_list[] = {
        {"i915_capabilities", i915_capabilities, 0},
        {"i915_gem_objects", i915_gem_object_info, 0},
@@ -1448,6 +1530,10 @@ int i915_debugfs_init(struct drm_minor *minor)
        if (ret)
                return ret;
 
+       ret = i915_hangcheck_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 +1543,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_hangcheck_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,
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 0239e99..e44a4a6 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -2092,6 +2092,7 @@ int i915_driver_load(struct drm_device *dev, unsigned 
long flags)
 
        setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
                    (unsigned long) dev);
+       atomic_set(&dev_priv->hangcheck_timeout, DRM_I915_HANGCHECK_PERIOD);
 
        spin_lock(&mchdev_lock);
        i915_mch_dev = dev_priv;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8a9fd91..f518e76 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -320,6 +320,7 @@ typedef struct drm_i915_private {
 #define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
        struct timer_list hangcheck_timer;
        int hangcheck_count;
+       atomic_t hangcheck_timeout;
        uint32_t last_acthd;
        uint32_t last_instdone;
        uint32_t last_instdone1;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index cb1f61d..48b140e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1777,8 +1777,11 @@ i915_add_request(struct intel_ring_buffer *ring,
        ring->outstanding_lazy_request = false;
 
        if (!dev_priv->mm.suspended) {
-               mod_timer(&dev_priv->hangcheck_timer,
-                         jiffies + 
msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+               int timeout = atomic_read(&dev_priv->hangcheck_timeout);
+               if (timeout) {
+                       mod_timer(&dev_priv->hangcheck_timer, jiffies +
+                               msecs_to_jiffies(timeout));
+               }
                if (was_empty)
                        queue_delayed_work(dev_priv->wq,
                                           &dev_priv->mm.retire_work, HZ);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b9fafe3..20316d3 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -352,6 +352,7 @@ static void notify_ring(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 seqno;
+       int timeout;
 
        if (ring->obj == NULL)
                return;
@@ -362,9 +363,12 @@ static void notify_ring(struct drm_device *dev,
        ring->irq_seqno = seqno;
        wake_up_all(&ring->irq_queue);
 
-       dev_priv->hangcheck_count = 0;
-       mod_timer(&dev_priv->hangcheck_timer,
-                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+       timeout = atomic_read(&dev_priv->hangcheck_timeout);
+       if (timeout) {
+               dev_priv->hangcheck_count = 0;
+               mod_timer(&dev_priv->hangcheck_timer, jiffies +
+                         msecs_to_jiffies(timeout));
+       }
 }
 
 static void gen6_pm_rps_work(struct work_struct *work)
@@ -1721,9 +1725,12 @@ void i915_hangcheck_elapsed(unsigned long data)
        }
 
 repeat:
+       /* should never be 0, we should drain the timer before setting * to 0 */
+       WARN_ON(atomic_read(&dev_priv->hangcheck_timeout) == 0);
+
        /* Reset timer case chip hangs without another request being added */
-       mod_timer(&dev_priv->hangcheck_timer,
-                 jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
+       mod_timer(&dev_priv->hangcheck_timer, jiffies +
+                 msecs_to_jiffies(atomic_read(&dev_priv->hangcheck_timeout));
 }
 
 /* drm_dma.h hooks
-- 
1.7.5.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to