[Intel-gfx] [PATCH] drm/i915: hangcheck timeout for debugfs
Ben Widawsky
ben at bwidawsk.net
Fri Jun 24 00:49:14 CEST 2011
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 <ben at bwidawsk.net>
Cc: Keith Packard <keithp at 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
More information about the Intel-gfx
mailing list