diff options
Diffstat (limited to 'sys/dev/pci/drm')
-rw-r--r-- | sys/dev/pci/drm/i915_drv.c | 30 | ||||
-rw-r--r-- | sys/dev/pci/drm/i915_drv.h | 4 |
2 files changed, 28 insertions, 6 deletions
diff --git a/sys/dev/pci/drm/i915_drv.c b/sys/dev/pci/drm/i915_drv.c index 74f874a7513..58e6e11e0e3 100644 --- a/sys/dev/pci/drm/i915_drv.c +++ b/sys/dev/pci/drm/i915_drv.c @@ -4385,7 +4385,7 @@ void inteldrm_hangcheck(void *arg) { struct inteldrm_softc *dev_priv = arg; - u_int32_t acthd; + u_int32_t acthd, instdone, instdone1; /* are we idle? no requests, or ring is empty */ if (TAILQ_EMPTY(&dev_priv->mm.request_list) || @@ -4395,15 +4395,30 @@ inteldrm_hangcheck(void *arg) return; } - if (IS_I965G(dev_priv)) + if (IS_I965G(dev_priv)) { acthd = I915_READ(ACTHD_I965); - else + instdone = I915_READ(INSTDONE_I965); + instdone1 = I915_READ(INSTDONE1); + } else { acthd = I915_READ(ACTHD); + instdone = I915_READ(INSTDONE); + instdone1 = 0; + } /* if we've hit ourselves before and the hardware hasn't moved, hung. */ - if (dev_priv->mm.last_acthd == acthd) { + if (dev_priv->mm.last_acthd == acthd && + dev_priv->mm.last_instdone == instdone && + dev_priv->mm.last_instdone1 == instdone1) { /* if that's twice we didn't hit it, then we're hung */ if (++dev_priv->mm.hang_cnt >= 2) { + if (!IS_GEN2(dev_priv)) { + u_int32_t tmp = I915_READ(PRB0_CTL); + if (tmp & RING_WAIT) { + I915_WRITE(PRB0_CTL, tmp); + (void)I915_READ(PRB0_CTL); + goto out; + } + } dev_priv->mm.hang_cnt = 0; /* XXX atomic */ dev_priv->mm.wedged = 1; @@ -4415,9 +4430,12 @@ inteldrm_hangcheck(void *arg) } } else { dev_priv->mm.hang_cnt = 0; - } - dev_priv->mm.last_acthd = acthd; + dev_priv->mm.last_acthd = acthd; + dev_priv->mm.last_instdone = instdone; + dev_priv->mm.last_instdone1 = instdone1; + } +out: /* Set ourselves up again, in case we haven't added another batch */ timeout_add_msec(&dev_priv->mm.hang_timer, 750); } diff --git a/sys/dev/pci/drm/i915_drv.h b/sys/dev/pci/drm/i915_drv.h index 263fdae42c3..bd3527fca5e 100644 --- a/sys/dev/pci/drm/i915_drv.h +++ b/sys/dev/pci/drm/i915_drv.h @@ -376,6 +376,8 @@ struct inteldrm_softc { /* for hangcheck */ int hang_cnt; u_int32_t last_acthd; + u_int32_t last_instdone; + u_int32_t last_instdone1; uint32_t next_gem_seqno; @@ -785,6 +787,8 @@ read64(struct inteldrm_softc *dev_priv, bus_size_t off) #define RING_VALID_MASK 0x00000001 #define RING_VALID 0x00000001 #define RING_INVALID 0x00000000 +#define RING_WAIT_I8XX (1<<0) /* gen2, PRBx_HEAD */ +#define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ #define PRB1_TAIL 0x02040 /* 915+ only */ #define PRB1_HEAD 0x02044 /* 915+ only */ #define PRB1_START 0x02048 /* 915+ only */ |