Re: [Intel-gfx] [PATCH v2] drm/i915: Stop parking the signaler around reset

2018-05-16 Thread Tvrtko Ursulin


On 16/05/2018 11:13, Chris Wilson wrote:

We cannot call kthread_park() from softirq context, so let's avoid it
entirely during the reset. We wanted to suspend the signaler so that it
would not mark a request as complete at the same time as we marked it as
being in error. Instead of parking the signaling, stop the engine from
advancing so that the GPU doesn't emit the breadcrumb for our chosen
"guilty" request.

v2: Refactor setting STOP_RING so that we don't have the same code thrice

Signed-off-by: Chris Wilson 
Cc: Mika Kuoppala 
Cc: Michał Winiarski 
CC: Michel Thierry 
Cc: Jeff McGee 
Cc: Tvrtko Ursulin 
---
  drivers/gpu/drm/i915/i915_gem.c | 14 
  drivers/gpu/drm/i915/intel_engine_cs.c  | 30 +
  drivers/gpu/drm/i915/intel_lrc.c|  6 +
  drivers/gpu/drm/i915/intel_ringbuffer.c |  2 ++
  drivers/gpu/drm/i915/intel_ringbuffer.h |  2 ++
  drivers/gpu/drm/i915/intel_uncore.c | 12 +++---
  6 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index abf661d40641..b0fe452ce17c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3015,18 +3015,6 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs 
*engine)
 */
intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL);
  
-	/*

-* Prevent the signaler thread from updating the request
-* state (by calling dma_fence_signal) as we are processing
-* the reset. The write from the GPU of the seqno is
-* asynchronous and the signaler thread may see a different
-* value to us and declare the request complete, even though
-* the reset routine have picked that request as the active
-* (incomplete) request. This conflict is not handled
-* gracefully!
-*/
-   kthread_park(engine->breadcrumbs.signaler);
-
request = engine->reset.prepare(engine);
if (request && request->fence.error == -EIO)
request = ERR_PTR(-EIO); /* Previous reset failed! */
@@ -3229,8 +3217,6 @@ void i915_gem_reset_finish_engine(struct intel_engine_cs 
*engine)
  {
engine->reset.finish(engine);
  
-	kthread_unpark(engine->breadcrumbs.signaler);

-
intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL);
  }
  
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c

index 6bfd7e3ed152..4d8105fcaca0 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -769,6 +769,36 @@ u64 intel_engine_get_last_batch_head(const struct 
intel_engine_cs *engine)
return bbaddr;
  }
  
+

+int intel_engine_stop_cs(struct intel_engine_cs *engine)
+{
+   struct drm_i915_private *dev_priv = engine->i915;
+   const u32 base = engine->mmio_base;
+   const i915_reg_t mode = RING_MI_MODE(base);
+   int err;
+
+   if (INTEL_GEN(dev_priv) < 3)
+   return -ENODEV;
+
+   GEM_TRACE("%s\n", engine->name);
+
+   I915_WRITE_FW(mode, _MASKED_BIT_ENABLE(STOP_RING));
+
+   err = 0;
+   if (__intel_wait_for_register_fw(dev_priv,
+mode, MODE_IDLE, MODE_IDLE,
+1000, 0,
+NULL)) {
+   GEM_TRACE("%s: timed out on STOP_RING -> IDLE\n", engine->name);
+   err = -ETIMEDOUT;
+   }
+
+   /* A final mmio read to let GPU writes be hopefully flushed to memory */
+   POSTING_READ_FW(mode);
+
+   return err;
+}
+
  const char *i915_cache_level_str(struct drm_i915_private *i915, int type)
  {
switch (type) {
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index cae10ebf9432..a973950e96b7 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1878,6 +1878,12 @@ execlists_reset_prepare(struct intel_engine_cs *engine)
if (request) {
unsigned long flags;
  
+		/*

+* Prevent the breadcrumb from advancing before we decide
+* which request is currently active.
+*/
+   intel_engine_stop_cs(engine);
+
spin_lock_irqsave(>timeline.lock, flags);
list_for_each_entry_from_reverse(request,
 >timeline.requests,
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c 
b/drivers/gpu/drm/i915/intel_ringbuffer.c
index af5a178366ed..6f200a747176 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -533,6 +533,8 @@ static int init_ring_common(struct intel_engine_cs *engine)
  
  static struct i915_request *reset_prepare(struct 

[Intel-gfx] [PATCH v2] drm/i915: Stop parking the signaler around reset

2018-05-16 Thread Chris Wilson
We cannot call kthread_park() from softirq context, so let's avoid it
entirely during the reset. We wanted to suspend the signaler so that it
would not mark a request as complete at the same time as we marked it as
being in error. Instead of parking the signaling, stop the engine from
advancing so that the GPU doesn't emit the breadcrumb for our chosen
"guilty" request.

v2: Refactor setting STOP_RING so that we don't have the same code thrice

Signed-off-by: Chris Wilson 
Cc: Mika Kuoppala 
Cc: Michał Winiarski 
CC: Michel Thierry 
Cc: Jeff McGee 
Cc: Tvrtko Ursulin 
---
 drivers/gpu/drm/i915/i915_gem.c | 14 
 drivers/gpu/drm/i915/intel_engine_cs.c  | 30 +
 drivers/gpu/drm/i915/intel_lrc.c|  6 +
 drivers/gpu/drm/i915/intel_ringbuffer.c |  2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |  2 ++
 drivers/gpu/drm/i915/intel_uncore.c | 12 +++---
 6 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index abf661d40641..b0fe452ce17c 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3015,18 +3015,6 @@ i915_gem_reset_prepare_engine(struct intel_engine_cs 
*engine)
 */
intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL);
 
-   /*
-* Prevent the signaler thread from updating the request
-* state (by calling dma_fence_signal) as we are processing
-* the reset. The write from the GPU of the seqno is
-* asynchronous and the signaler thread may see a different
-* value to us and declare the request complete, even though
-* the reset routine have picked that request as the active
-* (incomplete) request. This conflict is not handled
-* gracefully!
-*/
-   kthread_park(engine->breadcrumbs.signaler);
-
request = engine->reset.prepare(engine);
if (request && request->fence.error == -EIO)
request = ERR_PTR(-EIO); /* Previous reset failed! */
@@ -3229,8 +3217,6 @@ void i915_gem_reset_finish_engine(struct intel_engine_cs 
*engine)
 {
engine->reset.finish(engine);
 
-   kthread_unpark(engine->breadcrumbs.signaler);
-
intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c 
b/drivers/gpu/drm/i915/intel_engine_cs.c
index 6bfd7e3ed152..4d8105fcaca0 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -769,6 +769,36 @@ u64 intel_engine_get_last_batch_head(const struct 
intel_engine_cs *engine)
return bbaddr;
 }
 
+
+int intel_engine_stop_cs(struct intel_engine_cs *engine)
+{
+   struct drm_i915_private *dev_priv = engine->i915;
+   const u32 base = engine->mmio_base;
+   const i915_reg_t mode = RING_MI_MODE(base);
+   int err;
+
+   if (INTEL_GEN(dev_priv) < 3)
+   return -ENODEV;
+
+   GEM_TRACE("%s\n", engine->name);
+
+   I915_WRITE_FW(mode, _MASKED_BIT_ENABLE(STOP_RING));
+
+   err = 0;
+   if (__intel_wait_for_register_fw(dev_priv,
+mode, MODE_IDLE, MODE_IDLE,
+1000, 0,
+NULL)) {
+   GEM_TRACE("%s: timed out on STOP_RING -> IDLE\n", engine->name);
+   err = -ETIMEDOUT;
+   }
+
+   /* A final mmio read to let GPU writes be hopefully flushed to memory */
+   POSTING_READ_FW(mode);
+
+   return err;
+}
+
 const char *i915_cache_level_str(struct drm_i915_private *i915, int type)
 {
switch (type) {
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index cae10ebf9432..a973950e96b7 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1878,6 +1878,12 @@ execlists_reset_prepare(struct intel_engine_cs *engine)
if (request) {
unsigned long flags;
 
+   /*
+* Prevent the breadcrumb from advancing before we decide
+* which request is currently active.
+*/
+   intel_engine_stop_cs(engine);
+
spin_lock_irqsave(>timeline.lock, flags);
list_for_each_entry_from_reverse(request,
 >timeline.requests,
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c 
b/drivers/gpu/drm/i915/intel_ringbuffer.c
index af5a178366ed..6f200a747176 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -533,6 +533,8 @@ static int init_ring_common(struct intel_engine_cs *engine)
 
 static struct i915_request *reset_prepare(struct intel_engine_cs *engine)
 {
+