aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-09-25 05:19:17 -0400
committerChris Wilson <chris@chris-wilson.co.uk>2010-09-25 07:23:12 -0400
commit30dbf0c07ff4e3e21b827e2a9d6ff7eb34458819 (patch)
tree273083a7e570ce8ac43a327451afd4172645af7b /drivers/gpu/drm
parentf787a5f59e1b0e320a6b0a37e9a2e306551d1e40 (diff)
drm/i915: Adjust hangcheck EIO semantics
Owain Ainsworth reported an issue between the interaction of the hangcheck and userspace immediately (and permanently) falling back to s/w rasterisation. In order to break the mutex and begin resetting the GPU, we must abort the current operation (usually within the wait) and climb sufficiently far back up the call chain to drop the mutex. In his implementation, Owain has a loop within the ioctl handler to detect the hang and then sleep until the error handler has run. I've chosen to return to userspace and report an EAGAIN which should trigger the userspace ioctl handler to repeat the call (simply because it felt less invasive...). Before hitting a wedged GPU, we then wait upon completion of the error handler. Reported-by: Owain G. Ainsworth <zerooa@googlemail.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c66
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c6
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c2
4 files changed, 68 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2611e85bdd3d..f2ff258cdfd5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -363,6 +363,7 @@ typedef struct drm_i915_private {
363 spinlock_t error_lock; 363 spinlock_t error_lock;
364 struct drm_i915_error_state *first_error; 364 struct drm_i915_error_state *first_error;
365 struct work_struct error_work; 365 struct work_struct error_work;
366 struct completion error_completion;
366 struct workqueue_struct *wq; 367 struct workqueue_struct *wq;
367 368
368 /* Display functions */ 369 /* Display functions */
@@ -957,6 +958,7 @@ extern void i915_mem_takedown(struct mem_block **heap);
957extern void i915_mem_release(struct drm_device * dev, 958extern void i915_mem_release(struct drm_device * dev,
958 struct drm_file *file_priv, struct mem_block *heap); 959 struct drm_file *file_priv, struct mem_block *heap);
959/* i915_gem.c */ 960/* i915_gem.c */
961int i915_gem_check_is_wedged(struct drm_device *dev);
960int i915_gem_init_ioctl(struct drm_device *dev, void *data, 962int i915_gem_init_ioctl(struct drm_device *dev, void *data,
961 struct drm_file *file_priv); 963 struct drm_file *file_priv);
962int i915_gem_create_ioctl(struct drm_device *dev, void *data, 964int i915_gem_create_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 9185f098822d..a7283092c233 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -61,6 +61,37 @@ static void i915_gem_free_object_tail(struct drm_gem_object *obj);
61static LIST_HEAD(shrink_list); 61static LIST_HEAD(shrink_list);
62static DEFINE_SPINLOCK(shrink_list_lock); 62static DEFINE_SPINLOCK(shrink_list_lock);
63 63
64int
65i915_gem_check_is_wedged(struct drm_device *dev)
66{
67 struct drm_i915_private *dev_priv = dev->dev_private;
68 struct completion *x = &dev_priv->error_completion;
69 unsigned long flags;
70 int ret;
71
72 if (!atomic_read(&dev_priv->mm.wedged))
73 return 0;
74
75 ret = wait_for_completion_interruptible(x);
76 if (ret)
77 return ret;
78
79 /* Success, we reset the GPU! */
80 if (!atomic_read(&dev_priv->mm.wedged))
81 return 0;
82
83 /* GPU is hung, bump the completion count to account for
84 * the token we just consumed so that we never hit zero and
85 * end up waiting upon a subsequent completion event that
86 * will never happen.
87 */
88 spin_lock_irqsave(&x->wait.lock, flags);
89 x->done++;
90 spin_unlock_irqrestore(&x->wait.lock, flags);
91 return -EIO;
92}
93
94
64static inline bool 95static inline bool
65i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv) 96i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
66{ 97{
@@ -1848,15 +1879,15 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
1848 1879
1849 BUG_ON(seqno == 0); 1880 BUG_ON(seqno == 0);
1850 1881
1882 if (atomic_read(&dev_priv->mm.wedged))
1883 return -EAGAIN;
1884
1851 if (seqno == dev_priv->next_seqno) { 1885 if (seqno == dev_priv->next_seqno) {
1852 seqno = i915_add_request(dev, NULL, NULL, ring); 1886 seqno = i915_add_request(dev, NULL, NULL, ring);
1853 if (seqno == 0) 1887 if (seqno == 0)
1854 return -ENOMEM; 1888 return -ENOMEM;
1855 } 1889 }
1856 1890
1857 if (atomic_read(&dev_priv->mm.wedged))
1858 return -EIO;
1859
1860 if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) { 1891 if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
1861 if (HAS_PCH_SPLIT(dev)) 1892 if (HAS_PCH_SPLIT(dev))
1862 ier = I915_READ(DEIER) | I915_READ(GTIER); 1893 ier = I915_READ(DEIER) | I915_READ(GTIER);
@@ -1890,7 +1921,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
1890 trace_i915_gem_request_wait_end(dev, seqno); 1921 trace_i915_gem_request_wait_end(dev, seqno);
1891 } 1922 }
1892 if (atomic_read(&dev_priv->mm.wedged)) 1923 if (atomic_read(&dev_priv->mm.wedged))
1893 ret = -EIO; 1924 ret = -EAGAIN;
1894 1925
1895 if (ret && ret != -ERESTARTSYS) 1926 if (ret && ret != -ERESTARTSYS)
1896 DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n", 1927 DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
@@ -3569,13 +3600,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3569 struct drm_clip_rect *cliprects = NULL; 3600 struct drm_clip_rect *cliprects = NULL;
3570 struct drm_i915_gem_relocation_entry *relocs = NULL; 3601 struct drm_i915_gem_relocation_entry *relocs = NULL;
3571 struct drm_i915_gem_request *request = NULL; 3602 struct drm_i915_gem_request *request = NULL;
3572 int ret = 0, ret2, i, pinned = 0; 3603 int ret, ret2, i, pinned = 0;
3573 uint64_t exec_offset; 3604 uint64_t exec_offset;
3574 uint32_t reloc_index; 3605 uint32_t reloc_index;
3575 int pin_tries, flips; 3606 int pin_tries, flips;
3576 3607
3577 struct intel_ring_buffer *ring = NULL; 3608 struct intel_ring_buffer *ring = NULL;
3578 3609
3610 ret = i915_gem_check_is_wedged(dev);
3611 if (ret)
3612 return ret;
3613
3579#if WATCH_EXEC 3614#if WATCH_EXEC
3580 DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n", 3615 DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
3581 (int) args->buffers_ptr, args->buffer_count, args->batch_len); 3616 (int) args->buffers_ptr, args->buffer_count, args->batch_len);
@@ -3639,7 +3674,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
3639 3674
3640 if (atomic_read(&dev_priv->mm.wedged)) { 3675 if (atomic_read(&dev_priv->mm.wedged)) {
3641 mutex_unlock(&dev->struct_mutex); 3676 mutex_unlock(&dev->struct_mutex);
3642 ret = -EIO; 3677 ret = -EAGAIN;
3643 goto pre_mutex_err; 3678 goto pre_mutex_err;
3644 } 3679 }
3645 3680
@@ -4126,6 +4161,10 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
4126 struct drm_i915_gem_object *obj_priv; 4161 struct drm_i915_gem_object *obj_priv;
4127 int ret; 4162 int ret;
4128 4163
4164 ret = i915_gem_check_is_wedged(dev);
4165 if (ret)
4166 return ret;
4167
4129 mutex_lock(&dev->struct_mutex); 4168 mutex_lock(&dev->struct_mutex);
4130 4169
4131 obj = drm_gem_object_lookup(dev, file_priv, args->handle); 4170 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
@@ -4215,9 +4254,15 @@ int
4215i915_gem_busy_ioctl(struct drm_device *dev, void *data, 4254i915_gem_busy_ioctl(struct drm_device *dev, void *data,
4216 struct drm_file *file_priv) 4255 struct drm_file *file_priv)
4217{ 4256{
4257 struct drm_i915_private *dev_priv = dev->dev_private;
4218 struct drm_i915_gem_busy *args = data; 4258 struct drm_i915_gem_busy *args = data;
4219 struct drm_gem_object *obj; 4259 struct drm_gem_object *obj;
4220 struct drm_i915_gem_object *obj_priv; 4260 struct drm_i915_gem_object *obj_priv;
4261 int ret;
4262
4263 ret = i915_gem_check_is_wedged(dev);
4264 if (ret)
4265 return ret;
4221 4266
4222 obj = drm_gem_object_lookup(dev, file_priv, args->handle); 4267 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
4223 if (obj == NULL) { 4268 if (obj == NULL) {
@@ -4228,6 +4273,11 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
4228 4273
4229 mutex_lock(&dev->struct_mutex); 4274 mutex_lock(&dev->struct_mutex);
4230 4275
4276 if (atomic_read(&dev_priv->mm.wedged)) {
4277 ret = -EAGAIN;
4278 goto unlock;
4279 }
4280
4231 /* Count all active objects as busy, even if they are currently not used 4281 /* Count all active objects as busy, even if they are currently not used
4232 * by the gpu. Users of this interface expect objects to eventually 4282 * by the gpu. Users of this interface expect objects to eventually
4233 * become non-busy without any further actions, therefore emit any 4283 * become non-busy without any further actions, therefore emit any
@@ -4256,9 +4306,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
4256 args->busy = obj_priv->active; 4306 args->busy = obj_priv->active;
4257 } 4307 }
4258 4308
4309unlock:
4259 drm_gem_object_unreference(obj); 4310 drm_gem_object_unreference(obj);
4260 mutex_unlock(&dev->struct_mutex); 4311 mutex_unlock(&dev->struct_mutex);
4261 return 0; 4312 return ret;
4262} 4313}
4263 4314
4264int 4315int
@@ -4643,6 +4694,7 @@ i915_gem_load(struct drm_device *dev)
4643 INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); 4694 INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
4644 INIT_DELAYED_WORK(&dev_priv->mm.retire_work, 4695 INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
4645 i915_gem_retire_work_handler); 4696 i915_gem_retire_work_handler);
4697 init_completion(&dev_priv->error_completion);
4646 spin_lock(&shrink_list_lock); 4698 spin_lock(&shrink_list_lock);
4647 list_add(&dev_priv->mm.shrink_list, &shrink_list); 4699 list_add(&dev_priv->mm.shrink_list, &shrink_list);
4648 spin_unlock(&shrink_list_lock); 4700 spin_unlock(&shrink_list_lock);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index b09b157f6ada..8c9ffc4768ee 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -273,7 +273,11 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
273 drm_i915_private_t *dev_priv = dev->dev_private; 273 drm_i915_private_t *dev_priv = dev->dev_private;
274 struct drm_gem_object *obj; 274 struct drm_gem_object *obj;
275 struct drm_i915_gem_object *obj_priv; 275 struct drm_i915_gem_object *obj_priv;
276 int ret = 0; 276 int ret;
277
278 ret = i915_gem_check_is_wedged(dev);
279 if (ret)
280 return ret;
277 281
278 obj = drm_gem_object_lookup(dev, file_priv, args->handle); 282 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
279 if (obj == NULL) 283 if (obj == NULL)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 245a07e6f1a4..aaa0f1b9d6e1 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -406,6 +406,7 @@ static void i915_error_work_func(struct work_struct *work)
406 atomic_set(&dev_priv->mm.wedged, 0); 406 atomic_set(&dev_priv->mm.wedged, 0);
407 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); 407 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
408 } 408 }
409 complete_all(&dev_priv->error_completion);
409 } 410 }
410} 411}
411 412
@@ -869,6 +870,7 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
869 i915_report_and_clear_eir(dev); 870 i915_report_and_clear_eir(dev);
870 871
871 if (wedged) { 872 if (wedged) {
873 INIT_COMPLETION(dev_priv->error_completion);
872 atomic_set(&dev_priv->mm.wedged, 1); 874 atomic_set(&dev_priv->mm.wedged, 1);
873 875
874 /* 876 /*