diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 49 |
4 files changed, 65 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7a73b2941eb7..08a5048335e1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1447,6 +1447,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
1447 | if (!IS_IGDNG(dev)) | 1447 | if (!IS_IGDNG(dev)) |
1448 | intel_opregion_init(dev, 0); | 1448 | intel_opregion_init(dev, 0); |
1449 | 1449 | ||
1450 | setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, | ||
1451 | (unsigned long) dev); | ||
1450 | return 0; | 1452 | return 0; |
1451 | 1453 | ||
1452 | out_workqueue_free: | 1454 | out_workqueue_free: |
@@ -1467,6 +1469,7 @@ int i915_driver_unload(struct drm_device *dev) | |||
1467 | struct drm_i915_private *dev_priv = dev->dev_private; | 1469 | struct drm_i915_private *dev_priv = dev->dev_private; |
1468 | 1470 | ||
1469 | destroy_workqueue(dev_priv->wq); | 1471 | destroy_workqueue(dev_priv->wq); |
1472 | del_timer_sync(&dev_priv->hangcheck_timer); | ||
1470 | 1473 | ||
1471 | io_mapping_free(dev_priv->mm.gtt_mapping); | 1474 | io_mapping_free(dev_priv->mm.gtt_mapping); |
1472 | if (dev_priv->mm.gtt_mtrr >= 0) { | 1475 | if (dev_priv->mm.gtt_mtrr >= 0) { |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 933d832aeff7..afbcaa9866f4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -203,6 +203,12 @@ typedef struct drm_i915_private { | |||
203 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; | 203 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; |
204 | int vblank_pipe; | 204 | int vblank_pipe; |
205 | 205 | ||
206 | /* For hangcheck timer */ | ||
207 | #define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */ | ||
208 | struct timer_list hangcheck_timer; | ||
209 | int hangcheck_count; | ||
210 | uint32_t last_acthd; | ||
211 | |||
206 | bool cursor_needs_physical; | 212 | bool cursor_needs_physical; |
207 | 213 | ||
208 | struct drm_mm vram; | 214 | struct drm_mm vram; |
@@ -620,6 +626,7 @@ extern int i915_emit_box(struct drm_device *dev, | |||
620 | int i, int DR1, int DR4); | 626 | int i, int DR1, int DR4); |
621 | 627 | ||
622 | /* i915_irq.c */ | 628 | /* i915_irq.c */ |
629 | void i915_hangcheck_elapsed(unsigned long data); | ||
623 | extern int i915_irq_emit(struct drm_device *dev, void *data, | 630 | extern int i915_irq_emit(struct drm_device *dev, void *data, |
624 | struct drm_file *file_priv); | 631 | struct drm_file *file_priv); |
625 | extern int i915_irq_wait(struct drm_device *dev, void *data, | 632 | extern int i915_irq_wait(struct drm_device *dev, void *data, |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c70e91b51f67..579b3b04ff12 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -1584,8 +1584,11 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, | |||
1584 | 1584 | ||
1585 | } | 1585 | } |
1586 | 1586 | ||
1587 | if (was_empty && !dev_priv->mm.suspended) | 1587 | if (!dev_priv->mm.suspended) { |
1588 | queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); | 1588 | mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); |
1589 | if (was_empty) | ||
1590 | queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ); | ||
1591 | } | ||
1589 | return seqno; | 1592 | return seqno; |
1590 | } | 1593 | } |
1591 | 1594 | ||
@@ -3896,6 +3899,7 @@ i915_gem_idle(struct drm_device *dev) | |||
3896 | * We need to replace this with a semaphore, or something. | 3899 | * We need to replace this with a semaphore, or something. |
3897 | */ | 3900 | */ |
3898 | dev_priv->mm.suspended = 1; | 3901 | dev_priv->mm.suspended = 1; |
3902 | del_timer(&dev_priv->hangcheck_timer); | ||
3899 | 3903 | ||
3900 | /* Cancel the retire work handler, wait for it to finish if running | 3904 | /* Cancel the retire work handler, wait for it to finish if running |
3901 | */ | 3905 | */ |
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 | ||
885 | struct 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 | */ | ||
896 | void 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 | */ |
885 | static void igdng_irq_preinstall(struct drm_device *dev) | 934 | static void igdng_irq_preinstall(struct drm_device *dev) |