aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-01-07 16:06:07 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2011-01-11 15:44:55 -0500
commitbcfb2e285827bf0cfea8bbfad18a4fca57fbabae (patch)
treea73e795899cdef6ec8bdc0a41ee096b66928fba5
parentdb66e37d239b45f36a3f6495cf4ec49391b2c089 (diff)
drm/i915: Record the error batchbuffer on each ring
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c164
3 files changed, 50 insertions, 120 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 9c4cdc143be9..a7c194a837a3 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -750,7 +750,9 @@ static int i915_error_state(struct seq_file *m, void *unused)
750 if (error->batchbuffer[i]) { 750 if (error->batchbuffer[i]) {
751 struct drm_i915_error_object *obj = error->batchbuffer[i]; 751 struct drm_i915_error_object *obj = error->batchbuffer[i];
752 752
753 seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset); 753 seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
754 dev_priv->ring[i].name,
755 obj->gtt_offset);
754 offset = 0; 756 offset = 0;
755 for (page = 0; page < obj->page_count; page++) { 757 for (page = 0; page < obj->page_count; page++) {
756 for (elt = 0; elt < PAGE_SIZE/4; elt++) { 758 for (elt = 0; elt < PAGE_SIZE/4; elt++) {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 3e78314514a2..6c9a042737d6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -172,7 +172,7 @@ struct drm_i915_error_state {
172 int page_count; 172 int page_count;
173 u32 gtt_offset; 173 u32 gtt_offset;
174 u32 *pages[0]; 174 u32 *pages[0];
175 } *ringbuffer, *batchbuffer[2]; 175 } *ringbuffer, *batchbuffer[I915_NUM_RINGS];
176 struct drm_i915_error_buffer { 176 struct drm_i915_error_buffer {
177 size_t size; 177 size_t size;
178 u32 name; 178 u32 name;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index d431fc4fb84b..cf61235b858f 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -566,10 +566,9 @@ static void i915_error_work_func(struct work_struct *work)
566 566
567#ifdef CONFIG_DEBUG_FS 567#ifdef CONFIG_DEBUG_FS
568static struct drm_i915_error_object * 568static struct drm_i915_error_object *
569i915_error_object_create(struct drm_device *dev, 569i915_error_object_create(struct drm_i915_private *dev_priv,
570 struct drm_i915_gem_object *src) 570 struct drm_i915_gem_object *src)
571{ 571{
572 drm_i915_private_t *dev_priv = dev->dev_private;
573 struct drm_i915_error_object *dst; 572 struct drm_i915_error_object *dst;
574 int page, page_count; 573 int page, page_count;
575 u32 reloc_offset; 574 u32 reloc_offset;
@@ -642,52 +641,6 @@ i915_error_state_free(struct drm_device *dev,
642 kfree(error); 641 kfree(error);
643} 642}
644 643
645static u32
646i915_get_bbaddr(struct drm_device *dev, u32 *ring)
647{
648 u32 cmd;
649
650 if (IS_I830(dev) || IS_845G(dev))
651 cmd = MI_BATCH_BUFFER;
652 else if (INTEL_INFO(dev)->gen >= 4)
653 cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
654 MI_BATCH_NON_SECURE_I965);
655 else
656 cmd = (MI_BATCH_BUFFER_START | (2 << 6));
657
658 return ring[0] == cmd ? ring[1] : 0;
659}
660
661static u32
662i915_ringbuffer_last_batch(struct drm_device *dev,
663 struct intel_ring_buffer *ring)
664{
665 struct drm_i915_private *dev_priv = dev->dev_private;
666 u32 head, bbaddr;
667 u32 *val;
668
669 /* Locate the current position in the ringbuffer and walk back
670 * to find the most recently dispatched batch buffer.
671 */
672 head = I915_READ_HEAD(ring) & HEAD_ADDR;
673
674 val = (u32 *)(ring->virtual_start + head);
675 while (--val >= (u32 *)ring->virtual_start) {
676 bbaddr = i915_get_bbaddr(dev, val);
677 if (bbaddr)
678 return bbaddr;
679 }
680
681 val = (u32 *)(ring->virtual_start + ring->size);
682 while (--val >= (u32 *)ring->virtual_start) {
683 bbaddr = i915_get_bbaddr(dev, val);
684 if (bbaddr)
685 return bbaddr;
686 }
687
688 return 0;
689}
690
691static u32 capture_bo_list(struct drm_i915_error_buffer *err, 644static u32 capture_bo_list(struct drm_i915_error_buffer *err,
692 int count, 645 int count,
693 struct list_head *head) 646 struct list_head *head)
@@ -751,6 +704,36 @@ static void i915_gem_record_fences(struct drm_device *dev,
751 } 704 }
752} 705}
753 706
707static struct drm_i915_error_object *
708i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
709 struct intel_ring_buffer *ring)
710{
711 struct drm_i915_gem_object *obj;
712 u32 seqno;
713
714 if (!ring->get_seqno)
715 return NULL;
716
717 seqno = ring->get_seqno(ring);
718 list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
719 if (obj->ring != ring)
720 continue;
721
722 if (!i915_seqno_passed(obj->last_rendering_seqno, seqno))
723 continue;
724
725 if ((obj->base.read_domains & I915_GEM_DOMAIN_COMMAND) == 0)
726 continue;
727
728 /* We need to copy these to an anonymous buffer as the simplest
729 * method to avoid being overwritten by userspace.
730 */
731 return i915_error_object_create(dev_priv, obj);
732 }
733
734 return NULL;
735}
736
754/** 737/**
755 * i915_capture_error_state - capture an error record for later analysis 738 * i915_capture_error_state - capture an error record for later analysis
756 * @dev: drm device 739 * @dev: drm device
@@ -765,10 +748,8 @@ static void i915_capture_error_state(struct drm_device *dev)
765 struct drm_i915_private *dev_priv = dev->dev_private; 748 struct drm_i915_private *dev_priv = dev->dev_private;
766 struct drm_i915_gem_object *obj; 749 struct drm_i915_gem_object *obj;
767 struct drm_i915_error_state *error; 750 struct drm_i915_error_state *error;
768 struct drm_i915_gem_object *batchbuffer[2];
769 unsigned long flags; 751 unsigned long flags;
770 u32 bbaddr; 752 int i;
771 int count;
772 753
773 spin_lock_irqsave(&dev_priv->error_lock, flags); 754 spin_lock_irqsave(&dev_priv->error_lock, flags);
774 error = dev_priv->first_error; 755 error = dev_priv->first_error;
@@ -827,83 +808,30 @@ static void i915_capture_error_state(struct drm_device *dev)
827 } 808 }
828 i915_gem_record_fences(dev, error); 809 i915_gem_record_fences(dev, error);
829 810
830 bbaddr = i915_ringbuffer_last_batch(dev, &dev_priv->ring[RCS]); 811 /* Record the active batchbuffers */
831 812 for (i = 0; i < I915_NUM_RINGS; i++)
832 /* Grab the current batchbuffer, most likely to have crashed. */ 813 error->batchbuffer[i] =
833 batchbuffer[0] = NULL; 814 i915_error_first_batchbuffer(dev_priv,
834 batchbuffer[1] = NULL; 815 &dev_priv->ring[i]);
835 count = 0;
836 list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
837 if (batchbuffer[0] == NULL &&
838 bbaddr >= obj->gtt_offset &&
839 bbaddr < obj->gtt_offset + obj->base.size)
840 batchbuffer[0] = obj;
841
842 if (batchbuffer[1] == NULL &&
843 error->acthd >= obj->gtt_offset &&
844 error->acthd < obj->gtt_offset + obj->base.size)
845 batchbuffer[1] = obj;
846
847 count++;
848 }
849 /* Scan the other lists for completeness for those bizarre errors. */
850 if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
851 list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
852 if (batchbuffer[0] == NULL &&
853 bbaddr >= obj->gtt_offset &&
854 bbaddr < obj->gtt_offset + obj->base.size)
855 batchbuffer[0] = obj;
856
857 if (batchbuffer[1] == NULL &&
858 error->acthd >= obj->gtt_offset &&
859 error->acthd < obj->gtt_offset + obj->base.size)
860 batchbuffer[1] = obj;
861
862 if (batchbuffer[0] && batchbuffer[1])
863 break;
864 }
865 }
866 if (batchbuffer[0] == NULL || batchbuffer[1] == NULL) {
867 list_for_each_entry(obj, &dev_priv->mm.inactive_list, mm_list) {
868 if (batchbuffer[0] == NULL &&
869 bbaddr >= obj->gtt_offset &&
870 bbaddr < obj->gtt_offset + obj->base.size)
871 batchbuffer[0] = obj;
872
873 if (batchbuffer[1] == NULL &&
874 error->acthd >= obj->gtt_offset &&
875 error->acthd < obj->gtt_offset + obj->base.size)
876 batchbuffer[1] = obj;
877
878 if (batchbuffer[0] && batchbuffer[1])
879 break;
880 }
881 }
882
883 /* We need to copy these to an anonymous buffer as the simplest
884 * method to avoid being overwritten by userspace.
885 */
886 error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
887 if (batchbuffer[1] != batchbuffer[0])
888 error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
889 else
890 error->batchbuffer[1] = NULL;
891 816
892 /* Record the ringbuffer */ 817 /* Record the ringbuffer */
893 error->ringbuffer = i915_error_object_create(dev, 818 error->ringbuffer = i915_error_object_create(dev_priv,
894 dev_priv->ring[RCS].obj); 819 dev_priv->ring[RCS].obj);
895 820
896 /* Record buffers on the active and pinned lists. */ 821 /* Record buffers on the active and pinned lists. */
897 error->active_bo = NULL; 822 error->active_bo = NULL;
898 error->pinned_bo = NULL; 823 error->pinned_bo = NULL;
899 824
900 error->active_bo_count = count; 825 i = 0;
826 list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
827 i++;
828 error->active_bo_count = i;
901 list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list) 829 list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
902 count++; 830 i++;
903 error->pinned_bo_count = count - error->active_bo_count; 831 error->pinned_bo_count = i - error->active_bo_count;
904 832
905 if (count) { 833 if (i) {
906 error->active_bo = kmalloc(sizeof(*error->active_bo)*count, 834 error->active_bo = kmalloc(sizeof(*error->active_bo)*i,
907 GFP_ATOMIC); 835 GFP_ATOMIC);
908 if (error->active_bo) 836 if (error->active_bo)
909 error->pinned_bo = 837 error->pinned_bo =