diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-09-05 13:07:06 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-09-06 14:29:06 -0400 |
commit | 0ef82af7253c1929a3995f271b8b0db462d1a0c3 (patch) | |
tree | fb34eee409dffa5bfef725b00d38d6d54b8d31c8 /drivers/gpu/drm/i915/i915_drv.h | |
parent | 5e17ee74b541b56b5d4cfab6502a5116f224e32c (diff) |
drm/i915: Pad ringbuffer with NOOPs before wrapping
According to the docs, the ringbuffer is not allowed to wrap in the middle
of an instruction.
G45 PRM, Vol 1b, p101:
While the “free space” wrap may allow commands to be wrapped around the
end of the Ring Buffer, the wrap should only occur between commands.
Padding (with NOP) may be required to follow this restriction.
Do as commanded.
[Having seen bug reports where there is evidence of split commands, but
apparently the GPU has continued on merrily before a bizarre and untimely
death, this may or may not fix a few random hangs.]
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
CC: Eric Anholt <eric@anholt.net>
Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.h')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 43 |
1 files changed, 21 insertions, 22 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 76914ae65c3..2d5bce643e6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -85,7 +85,6 @@ struct drm_i915_gem_phys_object { | |||
85 | }; | 85 | }; |
86 | 86 | ||
87 | typedef struct _drm_i915_ring_buffer { | 87 | typedef struct _drm_i915_ring_buffer { |
88 | int tail_mask; | ||
89 | unsigned long Size; | 88 | unsigned long Size; |
90 | u8 *virtual_start; | 89 | u8 *virtual_start; |
91 | int head; | 90 | int head; |
@@ -790,33 +789,32 @@ extern void intel_modeset_cleanup(struct drm_device *dev); | |||
790 | 789 | ||
791 | #define I915_VERBOSE 0 | 790 | #define I915_VERBOSE 0 |
792 | 791 | ||
793 | #define RING_LOCALS unsigned int outring, ringmask, outcount; \ | 792 | #define RING_LOCALS volatile unsigned int *ring_virt__; |
794 | volatile char *virt; | 793 | |
795 | 794 | #define BEGIN_LP_RING(n) do { \ | |
796 | #define BEGIN_LP_RING(n) do { \ | 795 | int bytes__ = 4*(n); \ |
797 | if (I915_VERBOSE) \ | 796 | if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ |
798 | DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ | 797 | /* a wrap must occur between instructions so pad beforehand */ \ |
799 | if (dev_priv->ring.space < (n)*4) \ | 798 | if (unlikely (dev_priv->ring.tail + bytes__ > dev_priv->ring.Size)) \ |
800 | i915_wait_ring(dev, (n)*4, __func__); \ | 799 | i915_wrap_ring(dev); \ |
801 | outcount = 0; \ | 800 | if (unlikely (dev_priv->ring.space < bytes__)) \ |
802 | outring = dev_priv->ring.tail; \ | 801 | i915_wait_ring(dev, bytes__, __func__); \ |
803 | ringmask = dev_priv->ring.tail_mask; \ | 802 | ring_virt__ = (unsigned int *) \ |
804 | virt = dev_priv->ring.virtual_start; \ | 803 | (dev_priv->ring.virtual_start + dev_priv->ring.tail); \ |
804 | dev_priv->ring.tail += bytes__; \ | ||
805 | dev_priv->ring.tail &= dev_priv->ring.Size - 1; \ | ||
806 | dev_priv->ring.space -= bytes__; \ | ||
805 | } while (0) | 807 | } while (0) |
806 | 808 | ||
807 | #define OUT_RING(n) do { \ | 809 | #define OUT_RING(n) do { \ |
808 | if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ | 810 | if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ |
809 | *(volatile unsigned int *)(virt + outring) = (n); \ | 811 | *ring_virt__++ = (n); \ |
810 | outcount++; \ | ||
811 | outring += 4; \ | ||
812 | outring &= ringmask; \ | ||
813 | } while (0) | 812 | } while (0) |
814 | 813 | ||
815 | #define ADVANCE_LP_RING() do { \ | 814 | #define ADVANCE_LP_RING() do { \ |
816 | if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \ | 815 | if (I915_VERBOSE) \ |
817 | dev_priv->ring.tail = outring; \ | 816 | DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->ring.tail); \ |
818 | dev_priv->ring.space -= outcount * 4; \ | 817 | I915_WRITE(PRB0_TAIL, dev_priv->ring.tail); \ |
819 | I915_WRITE(PRB0_TAIL, outring); \ | ||
820 | } while(0) | 818 | } while(0) |
821 | 819 | ||
822 | /** | 820 | /** |
@@ -839,6 +837,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev); | |||
839 | #define I915_GEM_HWS_INDEX 0x20 | 837 | #define I915_GEM_HWS_INDEX 0x20 |
840 | #define I915_BREADCRUMB_INDEX 0x21 | 838 | #define I915_BREADCRUMB_INDEX 0x21 |
841 | 839 | ||
840 | extern int i915_wrap_ring(struct drm_device * dev); | ||
842 | extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | 841 | extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); |
843 | 842 | ||
844 | #define IS_I830(dev) ((dev)->pci_device == 0x3577) | 843 | #define IS_I830(dev) ((dev)->pci_device == 0x3577) |