@@ -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;
}
@@ -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);
@@ -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");
+ }
+ }
}
/**
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(-)