summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-04-13 17:35:10 +0100
committerBen Hutchings <ben@decadent.org.uk>2016-08-22 22:37:50 +0100
commit72877948df1bcaa19af6241cf98a3f772f3da491 (patch)
treec8a50602500baf64e25e78d99f81aba84cc799c8
parent8ce5d622b5820ef61ec3a54a355f183c4486dfe7 (diff)
drm/i915: Prevent machine death on Ivybridge context switching
commit e9135c4f08d9acb0f3da3ad2643b669dee3217c2 upstream. Two concurrent writes into the same register cacheline has the chance of killing the machine on Ivybridge and other gen7. This includes LRI emitted from the command parser. The MI_SET_CONTEXT itself serves as serialising barrier and prevents the pair of register writes in the first packet from triggering the fault. However, if a second switch-context immediately occurs then we may have two adjacent blocks of LRI to the same registers which may then trigger the hang. To counteract this we need to insert a delay after the second register write using SRM. This is easiest to reproduce with something like igt/gem_ctx_switch/interruptible that triggers back-to-back context switches (with no operations in between them in the command stream, which requires the execbuf operation to be interrupted after the MI_SET_CONTEXT) but can be observed sporadically elsewhere when running interruptible igt. No reports from the wild though, so it must be of low enough frequency that no one has correlated the random machine freezes with i915.ko The issue was introduced with commit 2c550183476dfa25641309ae9a28d30feed14379 [v3.19] Author: Chris Wilson <chris@chris-wilson.co.uk> Date: Tue Dec 16 10:02:27 2014 +0000 drm/i915: Disable PSMI sleep messages on all rings around context switches Testcase: igt/gem_ctx_switch/render-interruptible #ivb Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel@ffwll.ch> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Daniel Vetter <daniel@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/1460565315-7748-11-git-send-email-chris@chris-wilson.co.uk [bwh: Backported to 3.16: - Pass ring, not engine, to intel_ring_emit() - Register type is u32 not i915_reg_t - MI_STORE_REGISTER_MEM is a function-macro] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 14f92644828a..c1dc47202021 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -566,7 +566,7 @@ mi_set_context(struct intel_engine_cs *ring,
len = 4;
if (INTEL_INFO(ring->dev)->gen >= 7)
- len += 2 + (num_rings ? 4*num_rings + 2 : 0);
+ len += 2 + (num_rings ? 4*num_rings + 6 : 0);
ret = intel_ring_begin(ring, len);
if (ret)
@@ -605,15 +605,25 @@ mi_set_context(struct intel_engine_cs *ring,
if (INTEL_INFO(ring->dev)->gen >= 7) {
if (num_rings) {
struct intel_engine_cs *signaller;
+ u32 last_reg = 0; /* keep gcc quiet */
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
for_each_ring(signaller, to_i915(ring->dev), i) {
if (signaller == ring)
continue;
- intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+ last_reg = RING_PSMI_CTL(signaller->mmio_base);
+ intel_ring_emit(ring, last_reg);
intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
}
+
+ /* Insert a delay before the next switch! */
+ intel_ring_emit(ring,
+ MI_STORE_REGISTER_MEM(1) |
+ MI_SRM_LRM_GLOBAL_GTT);
+ intel_ring_emit(ring, last_reg);
+ intel_ring_emit(ring, ring->scratch.gtt_offset);
+ intel_ring_emit(ring, MI_NOOP);
}
intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
}