summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2008-06-23 10:16:35 -0700
committerKeith Packard <keithp@keithp.com>2008-06-23 10:16:35 -0700
commit626e9ba494b46f6e8352c9e461227187f335e229 (patch)
treec136ab45c0c34287ffd817ed489490b6261e83a3
parent1c2dd9826793579d5ef6f51fb9f5470c4af95548 (diff)
[intel-gem] Recover resources from wedged hardware.
Clean up queues, free objects. On the next entervt, unmark the hardware to let the user try again (presumably after resetting the chip). Someday we'll automatically recover...
-rw-r--r--linux-core/i915_gem.c23
-rw-r--r--shared-core/i915_drv.h9
2 files changed, 30 insertions, 2 deletions
diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c
index 4dfbd2a1..16a1b07e 100644
--- a/linux-core/i915_gem.c
+++ b/linux-core/i915_gem.c
@@ -653,7 +653,7 @@ i915_gem_retire_requests(struct drm_device *dev)
list);
retiring_seqno = request->seqno;
- if (i915_seqno_passed(seqno, retiring_seqno)) {
+ if (i915_seqno_passed(seqno, retiring_seqno) || dev_priv->mm.wedged) {
i915_gem_retire_request(dev, request);
list_del(&request->list);
@@ -697,10 +697,13 @@ i915_wait_request(struct drm_device *dev, uint32_t seqno)
i915_user_irq_on(dev_priv);
ret = wait_event_interruptible(dev_priv->irq_queue,
i915_seqno_passed(i915_get_gem_seqno(dev),
- seqno));
+ seqno) || dev_priv->mm.wedged);
i915_user_irq_off(dev_priv);
dev_priv->mm.waiting_gem_seqno = 0;
}
+ if (dev_priv->mm.wedged)
+ ret = -EIO;
+
if (ret)
DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
__func__, ret, seqno, i915_get_gem_seqno(dev));
@@ -1019,6 +1022,8 @@ i915_gem_evict_something(struct drm_device *dev)
list);
ret = i915_wait_request(dev, request->seqno);
+ if (ret)
+ break;
/* if waiting caused an object to become inactive,
* then loop around and wait for it. Otherwise, we
@@ -1822,6 +1827,13 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
mutex_lock(&dev->struct_mutex);
i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ if (dev_priv->mm.wedged) {
+ DRM_ERROR("Execbuf while wedged\n");
+ mutex_unlock(&dev->struct_mutex);
+ return -EIO;
+ }
+
if (dev_priv->mm.suspended) {
DRM_ERROR("Execbuf while VT-switched.\n");
mutex_unlock(&dev->struct_mutex);
@@ -2264,6 +2276,8 @@ i915_gem_idle(struct drm_device *dev)
if (last_seqno == cur_seqno) {
if (stuck++ > 100) {
DRM_ERROR("hardware wedged\n");
+ dev_priv->mm.wedged = 1;
+ DRM_WAKEUP(&dev_priv->irq_queue);
break;
}
}
@@ -2378,6 +2392,11 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
+ if (dev_priv->mm.wedged) {
+ DRM_ERROR("Renabling wedged hardware, good luck\n");
+ dev_priv->mm.wedged = 0;
+ }
+
ret = i915_gem_init_ringbuffer(dev);
if (ret != 0)
return ret;
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index 82d2c50c..a8d5b91e 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -309,6 +309,15 @@ typedef struct drm_i915_private {
* transitioned away from for kernel modesetting.
*/
int suspended;
+
+ /**
+ * Flag if the hardware appears to be wedged.
+ *
+ * This is set when attempts to idle the device timeout.
+ * It prevents command submission from occuring and makes
+ * every pending request fail
+ */
+ int wedged;
} mm;
} drm_i915_private_t;