From: Mika Kuoppala Date: Fri, 19 May 2017 09:13:40 +0000 (+0300) Subject: drm/i915/g4x: Improve gpu reset reliability X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=2c80353f3cd0cd4b28b17d55226e5914d2c0d5e1;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git drm/i915/g4x: Improve gpu reset reliability ELK seems to very picky about the preconditions to reset. Evidence on Eaglelake (8086:2e12 (rev 03)) shows that it does not like if reset occurs when there is active ring. Ville found out that there is workaround with name 'WaMediaResetMainRingCleanup' which suggests that we need to cleanup rings before resetting. It is unclear what cleanup exactly means but evidence shows that stopping the ring does have an effect on reset reliability. This patch makes reset successful on hangs induced by chained batches (the igt ones). Note that if the hang is inside a shader, it is possible that our attempts to stop the ring achieves anything. v2: zero ctl,head,tail also. bug ref. use driver debugs (Chris) v3: specify platform on testcases, comment tidyup (Chris) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=100942 Testcase: igt/gem_busy/*-hang #elk Testcase: igt/gem_ringfill/hang-* #elk Suggested-by: Ville Syrjälä Cc: Ville Syrjälä Cc: Chris Wilson Cc: Tomi Sarvela Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/20170519091340.21439-1-mika.kuoppala@intel.com --- diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 7922264e4fe1..df425bf629e3 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1427,6 +1427,35 @@ out: return ret; } +static void gen3_stop_rings(struct drm_i915_private *dev_priv) +{ + struct intel_engine_cs *engine; + enum intel_engine_id id; + + for_each_engine(engine, dev_priv, id) { + const u32 base = engine->mmio_base; + const i915_reg_t mode = RING_MI_MODE(base); + + I915_WRITE_FW(mode, _MASKED_BIT_ENABLE(STOP_RING)); + if (intel_wait_for_register_fw(dev_priv, + mode, + MODE_IDLE, + MODE_IDLE, + 500)) + DRM_DEBUG_DRIVER("%s: timed out on STOP_RING\n", + engine->name); + + I915_WRITE_FW(RING_CTL(base), 0); + I915_WRITE_FW(RING_HEAD(base), 0); + I915_WRITE_FW(RING_TAIL(base), 0); + + /* Check acts as a post */ + if (I915_READ_FW(RING_HEAD(base)) != 0) + DRM_DEBUG_DRIVER("%s: ring head not parked\n", + engine->name); + } +} + static bool i915_reset_complete(struct pci_dev *pdev) { u8 gdrst; @@ -1473,6 +1502,12 @@ static int g4x_do_reset(struct drm_i915_private *dev_priv, unsigned engine_mask) I915_READ(VDECCLK_GATE_D) | VCP_UNIT_CLOCK_GATE_DISABLE); POSTING_READ(VDECCLK_GATE_D); + /* We stop engines, otherwise we might get failed reset and a + * dead gpu (on elk). + * WaMediaResetMainRingCleanup:ctg,elk (presumably) + */ + gen3_stop_rings(dev_priv); + pci_write_config_byte(pdev, I915_GDRST, GRDOM_MEDIA | GRDOM_RESET_ENABLE); ret = wait_for(g4x_reset_complete(pdev), 500);