summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;