summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2023-01-18 23:55:07 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2023-01-18 23:55:07 +0000
commitcc976e21ce92a62d8aa8541db5a82d3abe21d2c9 (patch)
tree3c5bb7cdf7520d87797a82bc7b43d589fda3191f
parent989c9267c863f167a02e191546301193efcd2587 (diff)
drm/i915/gt: Reset twice
From Chris Wilson 4009502c091c1543ae8708a12d1a97583ae411ac in linux-6.1.y/6.1.7 d3de5616d36462a646f5b360ba82d3b09ff668eb in mainline linux
-rw-r--r--sys/dev/pci/drm/i915/gt/intel_reset.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/sys/dev/pci/drm/i915/gt/intel_reset.c b/sys/dev/pci/drm/i915/gt/intel_reset.c
index 8862e89d4b2..843b00b15af 100644
--- a/sys/dev/pci/drm/i915/gt/intel_reset.c
+++ b/sys/dev/pci/drm/i915/gt/intel_reset.c
@@ -278,6 +278,7 @@ out:
static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
{
struct intel_uncore *uncore = gt->uncore;
+ int loops = 2;
int err;
/*
@@ -285,18 +286,39 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
* for fifo space for the write or forcewake the chip for
* the read
*/
- intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
+ do {
+ intel_uncore_write_fw(uncore, GEN6_GDRST, hw_domain_mask);
- /* Wait for the device to ack the reset requests */
- err = __intel_wait_for_register_fw(uncore,
- GEN6_GDRST, hw_domain_mask, 0,
- 500, 0,
- NULL);
+ /*
+ * Wait for the device to ack the reset requests.
+ *
+ * On some platforms, e.g. Jasperlake, we see that the
+ * engine register state is not cleared until shortly after
+ * GDRST reports completion, causing a failure as we try
+ * to immediately resume while the internal state is still
+ * in flux. If we immediately repeat the reset, the second
+ * reset appears to serialise with the first, and since
+ * it is a no-op, the registers should retain their reset
+ * value. However, there is still a concern that upon
+ * leaving the second reset, the internal engine state
+ * is still in flux and not ready for resuming.
+ */
+ err = __intel_wait_for_register_fw(uncore, GEN6_GDRST,
+ hw_domain_mask, 0,
+ 2000, 0,
+ NULL);
+ } while (err == 0 && --loops);
if (err)
GT_TRACE(gt,
"Wait for 0x%08x engines reset failed\n",
hw_domain_mask);
+ /*
+ * As we have observed that the engine state is still volatile
+ * after GDRST is acked, impose a small delay to let everything settle.
+ */
+ udelay(50);
+
return err;
}