aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorBen Gamari <bgamari.foss@gmail.com>2009-09-14 17:48:44 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-09-17 17:36:01 -0400
commitf65d94211e2bcba17faf05a6a3809af0e4217767 (patch)
treea040777b0311b5c5a7a26f64c7d8ae9a6ac872f1 /drivers/gpu/drm/i915/i915_irq.c
parent22be172423b0007a02a06d70db8aeb4d9e64c6b3 (diff)
drm/i915: Add hangcheck timer
We set a periodic timer to check on the GPU, resetting it every time a batch is completed. If the timer elapses, we check acthd. If acthd hasn't changed in two timer periods, we assume the chip is wedged. This is implemented in such a way that it leaves the option open to employ adaptive timer intervals in the future. One could wait until several timer periods have elapsed before declaring the chip dead. If the chip comes back after several periods but before the "dead" threshold, the timer interval or dead threshold could be raised. It is important to note that while checking for active requests, we need to account for the fact that requests are removed from the list (i.e. retired) in a deferred work queue handler. This means that merely checking for an empty request_list is insufficient; the list could be non-empty yet the GPU still idle, causing the hangcheck timer to incorrectly mark the GPU as wedged (it took me a while to figure that out---sigh...) Signed-off-by: Ben Gamari <bgamari.foss@gmail.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 6c89f2ff2495..77e42e719d7d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -601,6 +601,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
601 if (iir & I915_USER_INTERRUPT) { 601 if (iir & I915_USER_INTERRUPT) {
602 dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); 602 dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
603 DRM_WAKEUP(&dev_priv->irq_queue); 603 DRM_WAKEUP(&dev_priv->irq_queue);
604 dev_priv->hangcheck_count = 0;
605 mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
604 } 606 }
605 607
606 if (pipea_stats & vblank_status) { 608 if (pipea_stats & vblank_status) {
@@ -880,6 +882,53 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
880 return -EINVAL; 882 return -EINVAL;
881} 883}
882 884
885struct drm_i915_gem_request *i915_get_tail_request(struct drm_device *dev) {
886 drm_i915_private_t *dev_priv = dev->dev_private;
887 return list_entry(dev_priv->mm.request_list.prev, struct drm_i915_gem_request, list);
888}
889
890/**
891 * This is called when the chip hasn't reported back with completed
892 * batchbuffers in a long time. The first time this is called we simply record
893 * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses
894 * again, we assume the chip is wedged and try to fix it.
895 */
896void i915_hangcheck_elapsed(unsigned long data)
897{
898 struct drm_device *dev = (struct drm_device *)data;
899 drm_i915_private_t *dev_priv = dev->dev_private;
900 uint32_t acthd;
901
902 if (!IS_I965G(dev))
903 acthd = I915_READ(ACTHD);
904 else
905 acthd = I915_READ(ACTHD_I965);
906
907 /* If all work is done then ACTHD clearly hasn't advanced. */
908 if (list_empty(&dev_priv->mm.request_list) ||
909 i915_seqno_passed(i915_get_gem_seqno(dev), i915_get_tail_request(dev)->seqno)) {
910 dev_priv->hangcheck_count = 0;
911 return;
912 }
913
914 if (dev_priv->last_acthd == acthd && dev_priv->hangcheck_count > 0) {
915 DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
916 dev_priv->mm.wedged = true; /* Hopefully this is atomic */
917 i915_handle_error(dev);
918 return;
919 }
920
921 /* Reset timer case chip hangs without another request being added */
922 mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
923
924 if (acthd != dev_priv->last_acthd)
925 dev_priv->hangcheck_count = 0;
926 else
927 dev_priv->hangcheck_count++;
928
929 dev_priv->last_acthd = acthd;
930}
931
883/* drm_dma.h hooks 932/* drm_dma.h hooks
884*/ 933*/
885static void igdng_irq_preinstall(struct drm_device *dev) 934static void igdng_irq_preinstall(struct drm_device *dev)