aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_irq.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2009-11-17 19:09:55 -0500
committerDave Airlie <airlied@redhat.com>2009-11-17 19:09:55 -0500
commit46557bef3f3834ac33031c7be27d39d90d507442 (patch)
tree5cfc4a9e1263fe0a15e516ca9695ee2f9b8899e4 /drivers/gpu/drm/i915/i915_irq.c
parent4efc50d697ed8d9a91f0005d922907a7b6c9290d (diff)
parentd91d8a3f88059d93e34ac70d059153ec69a9ffc7 (diff)
Merge branch 'drm-core-next' of ../linux-2.6 into drm-next
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c102
1 files changed, 94 insertions, 8 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 6c89f2ff2495..c3ceffa46ea0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -31,6 +31,7 @@
31#include "drm.h" 31#include "drm.h"
32#include "i915_drm.h" 32#include "i915_drm.h"
33#include "i915_drv.h" 33#include "i915_drv.h"
34#include "i915_trace.h"
34#include "intel_drv.h" 35#include "intel_drv.h"
35 36
36#define MAX_NOPID ((u32)~0) 37#define MAX_NOPID ((u32)~0)
@@ -279,7 +280,9 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
279 } 280 }
280 281
281 if (gt_iir & GT_USER_INTERRUPT) { 282 if (gt_iir & GT_USER_INTERRUPT) {
282 dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); 283 u32 seqno = i915_get_gem_seqno(dev);
284 dev_priv->mm.irq_gem_seqno = seqno;
285 trace_i915_gem_request_complete(dev, seqno);
283 DRM_WAKEUP(&dev_priv->irq_queue); 286 DRM_WAKEUP(&dev_priv->irq_queue);
284 } 287 }
285 288
@@ -302,12 +305,25 @@ static void i915_error_work_func(struct work_struct *work)
302 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, 305 drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
303 error_work); 306 error_work);
304 struct drm_device *dev = dev_priv->dev; 307 struct drm_device *dev = dev_priv->dev;
305 char *event_string = "ERROR=1"; 308 char *error_event[] = { "ERROR=1", NULL };
306 char *envp[] = { event_string, NULL }; 309 char *reset_event[] = { "RESET=1", NULL };
310 char *reset_done_event[] = { "ERROR=0", NULL };
307 311
308 DRM_DEBUG("generating error event\n"); 312 DRM_DEBUG("generating error event\n");
309 313 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
310 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); 314
315 if (atomic_read(&dev_priv->mm.wedged)) {
316 if (IS_I965G(dev)) {
317 DRM_DEBUG("resetting chip\n");
318 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
319 if (!i965_reset(dev, GDRST_RENDER)) {
320 atomic_set(&dev_priv->mm.wedged, 0);
321 kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
322 }
323 } else {
324 printk("reboot required\n");
325 }
326 }
311} 327}
312 328
313/** 329/**
@@ -372,7 +388,7 @@ out:
372 * so userspace knows something bad happened (should trigger collection 388 * so userspace knows something bad happened (should trigger collection
373 * of a ring dump etc.). 389 * of a ring dump etc.).
374 */ 390 */
375static void i915_handle_error(struct drm_device *dev) 391static void i915_handle_error(struct drm_device *dev, bool wedged)
376{ 392{
377 struct drm_i915_private *dev_priv = dev->dev_private; 393 struct drm_i915_private *dev_priv = dev->dev_private;
378 u32 eir = I915_READ(EIR); 394 u32 eir = I915_READ(EIR);
@@ -482,6 +498,16 @@ static void i915_handle_error(struct drm_device *dev)
482 I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT); 498 I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
483 } 499 }
484 500
501 if (wedged) {
502 atomic_set(&dev_priv->mm.wedged, 1);
503
504 /*
505 * Wakeup waiting processes so they don't hang
506 */
507 printk("i915: Waking up sleeping processes\n");
508 DRM_WAKEUP(&dev_priv->irq_queue);
509 }
510
485 queue_work(dev_priv->wq, &dev_priv->error_work); 511 queue_work(dev_priv->wq, &dev_priv->error_work);
486} 512}
487 513
@@ -527,7 +553,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
527 pipeb_stats = I915_READ(PIPEBSTAT); 553 pipeb_stats = I915_READ(PIPEBSTAT);
528 554
529 if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) 555 if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
530 i915_handle_error(dev); 556 i915_handle_error(dev, false);
531 557
532 /* 558 /*
533 * Clear the PIPE(A|B)STAT regs before the IIR 559 * Clear the PIPE(A|B)STAT regs before the IIR
@@ -599,8 +625,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
599 } 625 }
600 626
601 if (iir & I915_USER_INTERRUPT) { 627 if (iir & I915_USER_INTERRUPT) {
602 dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); 628 u32 seqno = i915_get_gem_seqno(dev);
629 dev_priv->mm.irq_gem_seqno = seqno;
630 trace_i915_gem_request_complete(dev, seqno);
603 DRM_WAKEUP(&dev_priv->irq_queue); 631 DRM_WAKEUP(&dev_priv->irq_queue);
632 dev_priv->hangcheck_count = 0;
633 mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
604 } 634 }
605 635
606 if (pipea_stats & vblank_status) { 636 if (pipea_stats & vblank_status) {
@@ -695,6 +725,16 @@ void i915_user_irq_put(struct drm_device *dev)
695 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); 725 spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
696} 726}
697 727
728void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
729{
730 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
731
732 if (dev_priv->trace_irq_seqno == 0)
733 i915_user_irq_get(dev);
734
735 dev_priv->trace_irq_seqno = seqno;
736}
737
698static int i915_wait_irq(struct drm_device * dev, int irq_nr) 738static int i915_wait_irq(struct drm_device * dev, int irq_nr)
699{ 739{
700 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 740 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -880,6 +920,52 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
880 return -EINVAL; 920 return -EINVAL;
881} 921}
882 922
923struct drm_i915_gem_request *i915_get_tail_request(struct drm_device *dev) {
924 drm_i915_private_t *dev_priv = dev->dev_private;
925 return list_entry(dev_priv->mm.request_list.prev, struct drm_i915_gem_request, list);
926}
927
928/**
929 * This is called when the chip hasn't reported back with completed
930 * batchbuffers in a long time. The first time this is called we simply record
931 * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses
932 * again, we assume the chip is wedged and try to fix it.
933 */
934void i915_hangcheck_elapsed(unsigned long data)
935{
936 struct drm_device *dev = (struct drm_device *)data;
937 drm_i915_private_t *dev_priv = dev->dev_private;
938 uint32_t acthd;
939
940 if (!IS_I965G(dev))
941 acthd = I915_READ(ACTHD);
942 else
943 acthd = I915_READ(ACTHD_I965);
944
945 /* If all work is done then ACTHD clearly hasn't advanced. */
946 if (list_empty(&dev_priv->mm.request_list) ||
947 i915_seqno_passed(i915_get_gem_seqno(dev), i915_get_tail_request(dev)->seqno)) {
948 dev_priv->hangcheck_count = 0;
949 return;
950 }
951
952 if (dev_priv->last_acthd == acthd && dev_priv->hangcheck_count > 0) {
953 DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
954 i915_handle_error(dev, true);
955 return;
956 }
957
958 /* Reset timer case chip hangs without another request being added */
959 mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
960
961 if (acthd != dev_priv->last_acthd)
962 dev_priv->hangcheck_count = 0;
963 else
964 dev_priv->hangcheck_count++;
965
966 dev_priv->last_acthd = acthd;
967}
968
883/* drm_dma.h hooks 969/* drm_dma.h hooks
884*/ 970*/
885static void igdng_irq_preinstall(struct drm_device *dev) 971static void igdng_irq_preinstall(struct drm_device *dev)