aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-05-03 08:48:16 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-05-05 13:45:00 -0400
commite5eb3d63c6182d3f21fbfc836ded748d49d521f9 (patch)
treefbd403fb63c664b6136390218809179da3d7e54e /drivers/gpu/drm/i915
parentc6ebd4c015a80991fe149a6a003ae4c83386e00e (diff)
drm/i915: add interface to simulate gpu hangs
gpu reset is a very important piece of our infrastructure. Unfortunately we only really it test by actually hanging the gpu, which often has bad side-effects for the entire system. And the gpu hang handling code is one of the rather complicated pieces of code we have, consisting of - hang detection - error capture - actual gpu reset - reset of all the gem bookkeeping - reinitialition of the entire gpu This patch adds a debugfs to selectively stopping rings by ceasing to update the hw tail pointer, which will result in the gpu no longer updating it's head pointer and eventually to the hangcheck firing. This way we can exercise the gpu hang code under controlled conditions without a dying gpu taking down the entire systems. Patch motivated by me forgetting to properly reinitialize ppgtt after a gpu reset. Usage: echo $((1 << $ringnum)) > i915_ring_stop # stops one ring echo 0xffffffff > i915_ring_stop # stops all, future-proof version then run whatever testload is desired. i915_ring_stop automatically resets after a gpu hang is detected to avoid hanging the gpu to fast and declaring it wedged. v2: Incorporate feedback from Chris Wilson. v3: Add the missing cleanup. v4: Fix up inconsistent size of ring_stop_read vs _write, noticed by Eugeni Dodonov. Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c65
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c4
4 files changed, 73 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index ae68ac1c488e..192b27e9046c 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1586,6 +1586,64 @@ static const struct file_operations i915_wedged_fops = {
1586}; 1586};
1587 1587
1588static ssize_t 1588static ssize_t
1589i915_ring_stop_read(struct file *filp,
1590 char __user *ubuf,
1591 size_t max,
1592 loff_t *ppos)
1593{
1594 struct drm_device *dev = filp->private_data;
1595 drm_i915_private_t *dev_priv = dev->dev_private;
1596 char buf[20];
1597 int len;
1598
1599 len = snprintf(buf, sizeof(buf),
1600 "0x%08x\n", dev_priv->stop_rings);
1601
1602 if (len > sizeof(buf))
1603 len = sizeof(buf);
1604
1605 return simple_read_from_buffer(ubuf, max, ppos, buf, len);
1606}
1607
1608static ssize_t
1609i915_ring_stop_write(struct file *filp,
1610 const char __user *ubuf,
1611 size_t cnt,
1612 loff_t *ppos)
1613{
1614 struct drm_device *dev = filp->private_data;
1615 struct drm_i915_private *dev_priv = dev->dev_private;
1616 char buf[20];
1617 int val = 0;
1618
1619 if (cnt > 0) {
1620 if (cnt > sizeof(buf) - 1)
1621 return -EINVAL;
1622
1623 if (copy_from_user(buf, ubuf, cnt))
1624 return -EFAULT;
1625 buf[cnt] = 0;
1626
1627 val = simple_strtoul(buf, NULL, 0);
1628 }
1629
1630 DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
1631
1632 mutex_lock(&dev->struct_mutex);
1633 dev_priv->stop_rings = val;
1634 mutex_unlock(&dev->struct_mutex);
1635
1636 return cnt;
1637}
1638
1639static const struct file_operations i915_ring_stop_fops = {
1640 .owner = THIS_MODULE,
1641 .open = simple_open,
1642 .read = i915_ring_stop_read,
1643 .write = i915_ring_stop_write,
1644 .llseek = default_llseek,
1645};
1646static ssize_t
1589i915_max_freq_read(struct file *filp, 1647i915_max_freq_read(struct file *filp,
1590 char __user *ubuf, 1648 char __user *ubuf,
1591 size_t max, 1649 size_t max,
@@ -1885,6 +1943,11 @@ int i915_debugfs_init(struct drm_minor *minor)
1885 &i915_cache_sharing_fops); 1943 &i915_cache_sharing_fops);
1886 if (ret) 1944 if (ret)
1887 return ret; 1945 return ret;
1946 ret = i915_debugfs_create(minor->debugfs_root, minor,
1947 "i915_ring_stop",
1948 &i915_ring_stop_fops);
1949 if (ret)
1950 return ret;
1888 1951
1889 return drm_debugfs_create_files(i915_debugfs_list, 1952 return drm_debugfs_create_files(i915_debugfs_list,
1890 I915_DEBUGFS_ENTRIES, 1953 I915_DEBUGFS_ENTRIES,
@@ -1903,6 +1966,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
1903 1, minor); 1966 1, minor);
1904 drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, 1967 drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
1905 1, minor); 1968 1, minor);
1969 drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops,
1970 1, minor);
1906} 1971}
1907 1972
1908#endif /* CONFIG_DEBUG_FS */ 1973#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 8a98f9a16418..90a84f9de8e9 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -800,6 +800,8 @@ int i915_reset(struct drm_device *dev, u8 flags)
800 if (!mutex_trylock(&dev->struct_mutex)) 800 if (!mutex_trylock(&dev->struct_mutex))
801 return -EBUSY; 801 return -EBUSY;
802 802
803 dev_priv->stop_rings = 0;
804
803 i915_gem_reset(dev); 805 i915_gem_reset(dev);
804 806
805 ret = -ENODEV; 807 ret = -ENODEV;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 00a20e985d28..090ec20293f2 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -412,6 +412,8 @@ typedef struct drm_i915_private {
412 uint32_t last_instdone; 412 uint32_t last_instdone;
413 uint32_t last_instdone1; 413 uint32_t last_instdone1;
414 414
415 unsigned int stop_rings;
416
415 unsigned long cfb_size; 417 unsigned long cfb_size;
416 unsigned int cfb_fb; 418 unsigned int cfb_fb;
417 enum plane cfb_plane; 419 enum plane cfb_plane;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 38096080a3de..3aabe8dfe5c5 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1210,7 +1210,11 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
1210 1210
1211void intel_ring_advance(struct intel_ring_buffer *ring) 1211void intel_ring_advance(struct intel_ring_buffer *ring)
1212{ 1212{
1213 struct drm_i915_private *dev_priv = ring->dev->dev_private;
1214
1213 ring->tail &= ring->size - 1; 1215 ring->tail &= ring->size - 1;
1216 if (dev_priv->stop_rings & intel_ring_flag(ring))
1217 return;
1214 ring->write_tail(ring, ring->tail); 1218 ring->write_tail(ring, ring->tail);
1215} 1219}
1216 1220