drm/i915: Workaround erratum on i830 for TAIL pointer within last 2 cachelines
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 22 Dec 2010 14:04:47 +0000 (14:04 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 11 Jan 2011 20:35:41 +0000 (20:35 +0000)
On i830 if the tail pointer is set to within 2 cachelines of the end of
the buffer, the chip may hang. So instead if the tail were to land in
that location, we pad the end of the buffer with NOPs, and start again
at the beginning.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h

index 56bc95c056dd9da2a06946e9d06a8d52f1978c85..2de0e45464c582014a46a5d3685b7e4879b848e6 100644 (file)
@@ -785,6 +785,14 @@ int intel_init_ring_buffer(struct drm_device *dev,
        if (ret)
                goto err_unmap;
 
+       /* Workaround an erratum on the i830 which causes a hang if
+        * the TAIL pointer points to within the last 2 cachelines
+        * of the buffer.
+        */
+       ring->effective_size = ring->size;
+       if (IS_I830(ring->dev))
+               ring->effective_size -= 128;
+
        return 0;
 
 err_unmap:
@@ -827,8 +835,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
 {
        unsigned int *virt;
-       int rem;
-       rem = ring->size - ring->tail;
+       int rem = ring->size - ring->tail;
 
        if (ring->space < rem) {
                int ret = intel_wait_ring_buffer(ring, rem);
@@ -895,7 +902,7 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
        int n = 4*num_dwords;
        int ret;
 
-       if (unlikely(ring->tail + n > ring->size)) {
+       if (unlikely(ring->tail + n > ring->effective_size)) {
                ret = intel_wrap_ring_buffer(ring);
                if (unlikely(ret))
                        return ret;
index 8e2e357ad6eec99e47ae826b1d4d80ff399b9809..bbbf505c8b569a0b1e105c5f83b214522ceb692b 100644 (file)
@@ -49,6 +49,7 @@ struct  intel_ring_buffer {
        u32             tail;
        int             space;
        int             size;
+       int             effective_size;
        struct intel_hw_status_page status_page;
 
        u32             irq_seqno;              /* last seq seem at irq time */