mirror of https://gitee.com/openkylin/linux.git
drm/i915: Wait for writes through the GTT to land before reading back
If we quickly switch from writing through the GTT to a read of the physical page directly with the CPU (e.g. performing relocations through the GTT and then running the command parser), we can observe that the writes are not visible to the CPU. It is not a coherency problem, as extensive investigations with clflush have demonstrated, but a mere timing issue - we have to wait for the GTT to complete it's write before we start our read from the CPU. The issue can be illustrated in userspace with: gtt = gem_mmap__gtt(fd, handle, 0, OBJECT_SIZE, PROT_READ | PROT_WRITE); cpu = gem_mmap__cpu(fd, handle, 0, OBJECT_SIZE, PROT_READ | PROT_WRITE); gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT); for (i = 0; i < OBJECT_SIZE / 64; i++) { int x = 16*i + (i%16); gtt[x] = i; clflush(&cpu[x], sizeof(cpu[x])); assert(cpu[x] == i); } Experimenting with that shows that this behaviour is indeed limited to recent Atom-class hardware. Testcase: igt/gem_exec_flush/basic-batch-default-cmd #byt Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20160818161718.27187-10-chris@chris-wilson.co.uk
This commit is contained in:
parent
a314d5cb4a
commit
3b5724d702
|
@ -3173,20 +3173,30 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj,
|
||||||
static void
|
static void
|
||||||
i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj)
|
i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
||||||
uint32_t old_write_domain;
|
uint32_t old_write_domain;
|
||||||
|
|
||||||
if (obj->base.write_domain != I915_GEM_DOMAIN_GTT)
|
if (obj->base.write_domain != I915_GEM_DOMAIN_GTT)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* No actual flushing is required for the GTT write domain. Writes
|
/* No actual flushing is required for the GTT write domain. Writes
|
||||||
* to it immediately go to main memory as far as we know, so there's
|
* to it "immediately" go to main memory as far as we know, so there's
|
||||||
* no chipset flush. It also doesn't land in render cache.
|
* no chipset flush. It also doesn't land in render cache.
|
||||||
*
|
*
|
||||||
* However, we do have to enforce the order so that all writes through
|
* However, we do have to enforce the order so that all writes through
|
||||||
* the GTT land before any writes to the device, such as updates to
|
* the GTT land before any writes to the device, such as updates to
|
||||||
* the GATT itself.
|
* the GATT itself.
|
||||||
|
*
|
||||||
|
* We also have to wait a bit for the writes to land from the GTT.
|
||||||
|
* An uncached read (i.e. mmio) seems to be ideal for the round-trip
|
||||||
|
* timing. This issue has only been observed when switching quickly
|
||||||
|
* between GTT writes and CPU reads from inside the kernel on recent hw,
|
||||||
|
* and it appears to only affect discrete GTT blocks (i.e. on LLC
|
||||||
|
* system agents we cannot reproduce this behaviour).
|
||||||
*/
|
*/
|
||||||
wmb();
|
wmb();
|
||||||
|
if (INTEL_GEN(dev_priv) >= 6 && !HAS_LLC(dev_priv))
|
||||||
|
POSTING_READ(RING_ACTHD(dev_priv->engine[RCS].mmio_base));
|
||||||
|
|
||||||
old_write_domain = obj->base.write_domain;
|
old_write_domain = obj->base.write_domain;
|
||||||
obj->base.write_domain = 0;
|
obj->base.write_domain = 0;
|
||||||
|
|
Loading…
Reference in New Issue