drm/i915: Insert a flush between batches if the breadcrumb was dropped
authorChris Wilson <chris@chris-wilson.co.uk>
Fri, 13 Jul 2012 13:14:08 +0000 (14:14 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 20 Jul 2012 10:21:40 +0000 (12:21 +0200)
If we drop the breadcrumb request after a batch due to a signal for
example we aim to fix it up at the next opportunity. In this case we
emit a second batchbuffer with no waits upon the first and so no
opportunity to insert the missing request, so we need to emit the
missing flush for coherency. (Note that that invalidating the render
cache is the same as flushing it, so there should have been no
observable corruption.)

Note that beside simply adding the missing flush, avoiding potential
render corruption, this will also fix at least parts of the problem
introduced by some funny interaction of these two commits:

commit de2b998552c1534e87bfbc51ec5734b02bc89020
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Wed Jul 4 22:52:50 2012 +0200

    drm/i915: don't return a spurious -EIO from intel_ring_begin

which allowed intel_ring_begin to return -ERESTARTSYS and

commit cc889e0f6ce6a63c62db17d702ecfed86d58083f
Author: Daniel Vetter <daniel.vetter@ffwll.ch>
Date:   Wed Jun 13 20:45:19 2012 +0200

    drm/i915: disable flushing_list/gpu_write_list

which essentially disabled the flushing list.

The issue happens when we submit a batch & emit it, but get
interrupted (thanks to the first patch) while trying to emit the
flush. On the next batch we still assume that the full gpu domain
handling is in effect and hence compute the invalidate&flushing
domains. But thanks to the 2nd patch we totally ignore these and only
invalidate all gpu domains, presuming that any required flushes have
been issued already.  Which is wrong and eventually results in us
updating the new write_domain values with the computed
pending_write_domain values, which leaves an object with write_domain
== 0 on the gpu_write_list.

As soon as we try to unbind that object, things blow up.

Fix this by emitting the missing flush according to the new
ring->gpu_caches_dirty flag.

Note that this does _not_ fix all the current cases where we end up
with an object on the flushing_list that can't be flushed.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=52040
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
[danvet: Add bug explanation to commit message.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_gem_execbuffer.c

index 88e2e114189ce0c97cddbcbc9b2c5f77177027d8..981e14f000e373eac39057239667dc299d80cf47 100644 (file)
@@ -885,11 +885,16 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
                        return ret;
        }
 
-       /* Unconditionally invalidate gpu caches. */
-       ret = i915_gem_flush_ring(ring, I915_GEM_GPU_DOMAINS, 0);
+       /* Unconditionally invalidate gpu caches and ensure that we do flush
+        * any residual writes from the previous batch.
+        */
+       ret = i915_gem_flush_ring(ring,
+                                 I915_GEM_GPU_DOMAINS,
+                                 ring->gpu_caches_dirty ? I915_GEM_GPU_DOMAINS : 0);
        if (ret)
                return ret;
 
+       ring->gpu_caches_dirty = false;
        return 0;
 }