aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_dma.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-09-05 13:07:06 -0400
committerEric Anholt <eric@anholt.net>2009-09-06 14:29:06 -0400
commit0ef82af7253c1929a3995f271b8b0db462d1a0c3 (patch)
treefb34eee409dffa5bfef725b00d38d6d54b8d31c8 /drivers/gpu/drm/i915/i915_dma.c
parent5e17ee74b541b56b5d4cfab6502a5116f224e32c (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_dma.c')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 50d1f782768c..f135bdcc6d5b 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -80,6 +80,34 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
80 return -EBUSY; 80 return -EBUSY;
81} 81}
82 82
83/* As a ringbuffer is only allowed to wrap between instructions, fill
84 * the tail with NOOPs.
85 */
86int i915_wrap_ring(struct drm_device *dev)
87{
88 drm_i915_private_t *dev_priv = dev->dev_private;
89 volatile unsigned int *virt;
90 int rem;
91
92 rem = dev_priv->ring.Size - dev_priv->ring.tail;
93 if (dev_priv->ring.space < rem) {
94 int ret = i915_wait_ring(dev, rem, __func__);
95 if (ret)
96 return ret;
97 }
98 dev_priv->ring.space -= rem;
99
100 virt = (unsigned int *)
101 (dev_priv->ring.virtual_start + dev_priv->ring.tail);
102 rem /= 4;
103 while (rem--)
104 *virt++ = MI_NOOP;
105
106 dev_priv->ring.tail = 0;
107
108 return 0;
109}
110
83/** 111/**
84 * Sets up the hardware status page for devices that need a physical address 112 * Sets up the hardware status page for devices that need a physical address
85 * in the register. 113 * in the register.
@@ -200,7 +228,6 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
200 } 228 }
201 229
202 dev_priv->ring.Size = init->ring_size; 230 dev_priv->ring.Size = init->ring_size;
203 dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
204 231
205 dev_priv->ring.map.offset = init->ring_start; 232 dev_priv->ring.map.offset = init->ring_start;
206 dev_priv->ring.map.size = init->ring_size; 233 dev_priv->ring.map.size = init->ring_size;