drm/i915/ringbuffer: Handle wrapping of the autoreported HEAD
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 9 Dec 2010 12:56:37 +0000 (12:56 +0000)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 9 Dec 2010 12:53:19 +0000 (12:53 +0000)
If the tail advances beyond the autoreport HEAD value, then we need to
fallback to an uncached read of the HEAD register in order to ascertain
the correct amount of remaining space in the ringbuffer.

Reported-by: Fang, Xun <xunx.fang@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=32259
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 89a65be..31cd7e3 100644 (file)
@@ -696,20 +696,17 @@ int intel_wait_ring_buffer(struct drm_device *dev,
        drm_i915_private_t *dev_priv = dev->dev_private;
        u32 head;
 
-       head = intel_read_status_page(ring, 4);
-       if (head) {
-               ring->head = head & HEAD_ADDR;
-               ring->space = ring->head - (ring->tail + 8);
-               if (ring->space < 0)
-                       ring->space += ring->size;
-               if (ring->space >= n)
-                       return 0;
-       }
-
        trace_i915_ring_wait_begin (dev);
        end = jiffies + 3 * HZ;
        do {
-               ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+               /* If the reported head position has wrapped or hasn't advanced,
+                * fallback to the slow and accurate path.
+                */
+               head = intel_read_status_page(ring, 4);
+               if (head < ring->actual_head)
+                       head = I915_READ_HEAD(ring);
+               ring->actual_head = head;
+               ring->head = head & HEAD_ADDR;
                ring->space = ring->head - (ring->tail + 8);
                if (ring->space < 0)
                        ring->space += ring->size;
index 3126c26..d2cd0f1 100644 (file)
@@ -30,8 +30,9 @@ struct  intel_ring_buffer {
        struct          drm_device *dev;
        struct          drm_gem_object *gem_object;
 
-       unsigned int    head;
-       unsigned int    tail;
+       u32             actual_head;
+       u32             head;
+       u32             tail;
        int             space;
        struct intel_hw_status_page status_page;