diff mbox

[6/6] drm/i915: Hookup chip reset in error handler

Message ID 1252949236-2906-7-git-send-email-bgamari.foss@gmail.com (mailing list archive)
State Superseded
Headers show

Commit Message

Ben Gamari Sept. 14, 2009, 5:27 p.m. UTC
This patch uses the previously introduced chip reset logic to reset the
chip when an error event is detected.

Signed-off-by: Ben Gamari <bgamari.foss@gmail.com>
---
 drivers/gpu/drm/i915/i915_drv.c |    7 ++++---
 drivers/gpu/drm/i915/i915_drv.h |    2 +-
 drivers/gpu/drm/i915/i915_irq.c |   21 +++++++++++++++++----
 3 files changed, 22 insertions(+), 8 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 93f50b3..a9d7ee1 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -132,7 +132,7 @@  static int i915_resume(struct drm_device *dev)
  * @dev: drm device to reset
  * @flags: reset domains
  *
- * Reset the chip.  Useful if a hang is detected.
+ * Reset the chip.  Useful if a hang is detected. Return nonzero if reset fails.
  *
  * Procedure is fairly simple:
  *   - reset the chip using the reset reg
@@ -142,7 +142,7 @@  static int i915_resume(struct drm_device *dev)
  *   - re-init interrupt state
  *   - re-init display
  */
-void i965_reset(struct drm_device *dev, u8 flags)
+int i965_reset(struct drm_device *dev, u8 flags)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long timeout;
@@ -184,7 +184,7 @@  void i965_reset(struct drm_device *dev, u8 flags)
 		if (gdrst & 0x1) {
 			WARN(true, "i915: Failed to reset chip\n");
 			mutex_unlock(&dev->struct_mutex);
-			return;
+			return 1;
 		}
 	} else {
 		DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
@@ -246,6 +246,7 @@  void i965_reset(struct drm_device *dev, u8 flags)
 		i915_restore_display(dev);
 
 	mutex_unlock(&dev->struct_mutex);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8797777..42142f2 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -624,7 +624,7 @@  extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
 extern int i915_emit_box(struct drm_device *dev,
 			 struct drm_clip_rect *boxes,
 			 int i, int DR1, int DR4);
-extern void i965_reset(struct drm_device *dev, u8 flags);
+extern int i965_reset(struct drm_device *dev, u8 flags);
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index dbfcf0a..a47e9f3 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -302,12 +302,25 @@  static void i915_error_work_func(struct work_struct *work)
 	drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
 						    error_work);
 	struct drm_device *dev = dev_priv->dev;
-	char *event_string = "ERROR=1";
-	char *envp[] = { event_string, NULL };
+	char *error_event[] = { "ERROR=1", NULL };
+	char *reset_event[] = { "RESET=1", NULL };
+	char *reset_done_event[] = { "ERROR=0", NULL };
 
 	DRM_DEBUG("generating error event\n");
+	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
-	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
+	if (dev_priv->mm.wedged) {
+		if (IS_I965G(dev)) {
+			DRM_DEBUG("resetting chip\n");
+			kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
+			if (!i965_reset(dev, GDRST_RENDER)) {
+				dev_priv->mm.wedged = 0;
+				kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
+			}
+		} else {
+			printk("reboot required\n");
+		}
+	}
 }
 
 /**