[Intel-gfx] [PATCH 12/23] drm/i915: Rework intel_context pinning to do everything outside of pin_mutex

2020-05-20 Thread Maarten Lankhorst
Instead of doing everything inside of pin_mutex, we move all pinning
outside. Because i915_active has its own reference counting and
pinning is also having the same issues vs mutexes, we make sure
everything is pinned first, so the pinning in i915_active only needs
to bump refcounts. This allows us to take pin refcounts correctly
all the time.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/i915/gt/intel_context.c   | 232 +++---
 drivers/gpu/drm/i915/gt/intel_context_types.h |   4 +-
 drivers/gpu/drm/i915/gt/intel_lrc.c   |  34 ++-
 .../gpu/drm/i915/gt/intel_ring_submission.c   |  13 +-
 drivers/gpu/drm/i915/gt/mock_engine.c |  13 +-
 5 files changed, 190 insertions(+), 106 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
b/drivers/gpu/drm/i915/gt/intel_context.c
index e4aece20bc80..c039e87a46c4 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -93,79 +93,6 @@ static void intel_context_active_release(struct 
intel_context *ce)
i915_active_release(>active);
 }
 
-int __intel_context_do_pin(struct intel_context *ce)
-{
-   int err;
-
-   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
-   err = intel_context_alloc_state(ce);
-   if (err)
-   return err;
-   }
-
-   err = i915_active_acquire(>active);
-   if (err)
-   return err;
-
-   if (mutex_lock_interruptible(>pin_mutex)) {
-   err = -EINTR;
-   goto out_release;
-   }
-
-   if (unlikely(intel_context_is_closed(ce))) {
-   err = -ENOENT;
-   goto out_unlock;
-   }
-
-   if (likely(!atomic_add_unless(>pin_count, 1, 0))) {
-   err = intel_context_active_acquire(ce);
-   if (unlikely(err))
-   goto out_unlock;
-
-   err = ce->ops->pin(ce);
-   if (unlikely(err))
-   goto err_active;
-
-   CE_TRACE(ce, "pin ring:{start:%08x, head:%04x, tail:%04x}\n",
-i915_ggtt_offset(ce->ring->vma),
-ce->ring->head, ce->ring->tail);
-
-   smp_mb__before_atomic(); /* flush pin before it is visible */
-   atomic_inc(>pin_count);
-   }
-
-   GEM_BUG_ON(!intel_context_is_pinned(ce)); /* no overflow! */
-   GEM_BUG_ON(i915_active_is_idle(>active));
-   goto out_unlock;
-
-err_active:
-   intel_context_active_release(ce);
-out_unlock:
-   mutex_unlock(>pin_mutex);
-out_release:
-   i915_active_release(>active);
-   return err;
-}
-
-void intel_context_unpin(struct intel_context *ce)
-{
-   if (!atomic_dec_and_test(>pin_count))
-   return;
-
-   CE_TRACE(ce, "unpin\n");
-   ce->ops->unpin(ce);
-
-   /*
-* Once released, we may asynchronously drop the active reference.
-* As that may be the only reference keeping the context alive,
-* take an extra now so that it is not freed before we finish
-* dereferencing it.
-*/
-   intel_context_get(ce);
-   intel_context_active_release(ce);
-   intel_context_put(ce);
-}
-
 static int __context_pin_state(struct i915_vma *vma)
 {
unsigned int bias = i915_ggtt_pin_bias(vma) | PIN_OFFSET_BIAS;
@@ -225,6 +152,138 @@ static void __ring_retire(struct intel_ring *ring)
i915_active_release(>vma->active);
 }
 
+static int intel_context_pre_pin(struct intel_context *ce)
+{
+   int err;
+
+   CE_TRACE(ce, "active\n");
+
+   err = __ring_active(ce->ring);
+   if (err)
+   return err;
+
+   err = intel_timeline_pin(ce->timeline);
+   if (err)
+   goto err_ring;
+
+   if (!ce->state)
+   return 0;
+
+   err = __context_pin_state(ce->state);
+   if (err)
+   goto err_timeline;
+
+
+   return 0;
+
+err_timeline:
+   intel_timeline_unpin(ce->timeline);
+err_ring:
+   __ring_retire(ce->ring);
+   return err;
+}
+
+static void intel_context_post_unpin(struct intel_context *ce)
+{
+   if (ce->state)
+   __context_unpin_state(ce->state);
+
+   intel_timeline_unpin(ce->timeline);
+   __ring_retire(ce->ring);
+}
+
+int __intel_context_do_pin(struct intel_context *ce)
+{
+   bool handoff = false;
+   void *vaddr;
+   int err = 0;
+
+   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
+   err = intel_context_alloc_state(ce);
+   if (err)
+   return err;
+   }
+
+   /*
+* We always pin the context/ring/timeline here, to ensure a pin
+* refcount for __intel_context_active(), which prevent a lock
+* inversion of ce->pin_mutex vs dma_resv_lock().
+*/
+   err = intel_context_pre_pin(ce);
+   if (err)
+   return err;
+
+   err = i915_active_acquire(>active);
+   

[Intel-gfx] [PATCH 12/23] drm/i915: Rework intel_context pinning to do everything outside of pin_mutex

2020-05-11 Thread Maarten Lankhorst
Instead of doing everything inside of pin_mutex, we move all pinning
outside. Because i915_active has its own reference counting and
pinning is also having the same issues vs mutexes, we make sure
everything is pinned first, so the pinning in i915_active only needs
to bump refcounts. This allows us to take pin refcounts correctly
all the time.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/i915/gt/intel_context.c   | 232 +++---
 drivers/gpu/drm/i915/gt/intel_context_types.h |   4 +-
 drivers/gpu/drm/i915/gt/intel_lrc.c   |  34 ++-
 .../gpu/drm/i915/gt/intel_ring_submission.c   |  13 +-
 drivers/gpu/drm/i915/gt/mock_engine.c |  13 +-
 5 files changed, 190 insertions(+), 106 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
b/drivers/gpu/drm/i915/gt/intel_context.c
index e4aece20bc80..c039e87a46c4 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -93,79 +93,6 @@ static void intel_context_active_release(struct 
intel_context *ce)
i915_active_release(>active);
 }
 
-int __intel_context_do_pin(struct intel_context *ce)
-{
-   int err;
-
-   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
-   err = intel_context_alloc_state(ce);
-   if (err)
-   return err;
-   }
-
-   err = i915_active_acquire(>active);
-   if (err)
-   return err;
-
-   if (mutex_lock_interruptible(>pin_mutex)) {
-   err = -EINTR;
-   goto out_release;
-   }
-
-   if (unlikely(intel_context_is_closed(ce))) {
-   err = -ENOENT;
-   goto out_unlock;
-   }
-
-   if (likely(!atomic_add_unless(>pin_count, 1, 0))) {
-   err = intel_context_active_acquire(ce);
-   if (unlikely(err))
-   goto out_unlock;
-
-   err = ce->ops->pin(ce);
-   if (unlikely(err))
-   goto err_active;
-
-   CE_TRACE(ce, "pin ring:{start:%08x, head:%04x, tail:%04x}\n",
-i915_ggtt_offset(ce->ring->vma),
-ce->ring->head, ce->ring->tail);
-
-   smp_mb__before_atomic(); /* flush pin before it is visible */
-   atomic_inc(>pin_count);
-   }
-
-   GEM_BUG_ON(!intel_context_is_pinned(ce)); /* no overflow! */
-   GEM_BUG_ON(i915_active_is_idle(>active));
-   goto out_unlock;
-
-err_active:
-   intel_context_active_release(ce);
-out_unlock:
-   mutex_unlock(>pin_mutex);
-out_release:
-   i915_active_release(>active);
-   return err;
-}
-
-void intel_context_unpin(struct intel_context *ce)
-{
-   if (!atomic_dec_and_test(>pin_count))
-   return;
-
-   CE_TRACE(ce, "unpin\n");
-   ce->ops->unpin(ce);
-
-   /*
-* Once released, we may asynchronously drop the active reference.
-* As that may be the only reference keeping the context alive,
-* take an extra now so that it is not freed before we finish
-* dereferencing it.
-*/
-   intel_context_get(ce);
-   intel_context_active_release(ce);
-   intel_context_put(ce);
-}
-
 static int __context_pin_state(struct i915_vma *vma)
 {
unsigned int bias = i915_ggtt_pin_bias(vma) | PIN_OFFSET_BIAS;
@@ -225,6 +152,138 @@ static void __ring_retire(struct intel_ring *ring)
i915_active_release(>vma->active);
 }
 
+static int intel_context_pre_pin(struct intel_context *ce)
+{
+   int err;
+
+   CE_TRACE(ce, "active\n");
+
+   err = __ring_active(ce->ring);
+   if (err)
+   return err;
+
+   err = intel_timeline_pin(ce->timeline);
+   if (err)
+   goto err_ring;
+
+   if (!ce->state)
+   return 0;
+
+   err = __context_pin_state(ce->state);
+   if (err)
+   goto err_timeline;
+
+
+   return 0;
+
+err_timeline:
+   intel_timeline_unpin(ce->timeline);
+err_ring:
+   __ring_retire(ce->ring);
+   return err;
+}
+
+static void intel_context_post_unpin(struct intel_context *ce)
+{
+   if (ce->state)
+   __context_unpin_state(ce->state);
+
+   intel_timeline_unpin(ce->timeline);
+   __ring_retire(ce->ring);
+}
+
+int __intel_context_do_pin(struct intel_context *ce)
+{
+   bool handoff = false;
+   void *vaddr;
+   int err = 0;
+
+   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
+   err = intel_context_alloc_state(ce);
+   if (err)
+   return err;
+   }
+
+   /*
+* We always pin the context/ring/timeline here, to ensure a pin
+* refcount for __intel_context_active(), which prevent a lock
+* inversion of ce->pin_mutex vs dma_resv_lock().
+*/
+   err = intel_context_pre_pin(ce);
+   if (err)
+   return err;
+
+   err = i915_active_acquire(>active);
+   

[Intel-gfx] [PATCH 12/23] drm/i915: Rework intel_context pinning to do everything outside of pin_mutex

2020-04-08 Thread Maarten Lankhorst
Instead of doing everything inside of pin_mutex, we move all pinning
outside. Because i915_active has its own reference counting and
pinning is also having the same issues vs mutexes, we make sure
everything is pinned first, so the pinning in i915_active only needs
to bump refcounts. This allows us to take pin refcounts correctly
all the time.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/i915/gt/intel_context.c   | 232 +++---
 drivers/gpu/drm/i915/gt/intel_context_types.h |   4 +-
 drivers/gpu/drm/i915/gt/intel_lrc.c   |  34 ++-
 .../gpu/drm/i915/gt/intel_ring_submission.c   |  13 +-
 drivers/gpu/drm/i915/gt/mock_engine.c |  13 +-
 5 files changed, 190 insertions(+), 106 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
b/drivers/gpu/drm/i915/gt/intel_context.c
index e4aece20bc80..c039e87a46c4 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -93,79 +93,6 @@ static void intel_context_active_release(struct 
intel_context *ce)
i915_active_release(>active);
 }
 
-int __intel_context_do_pin(struct intel_context *ce)
-{
-   int err;
-
-   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
-   err = intel_context_alloc_state(ce);
-   if (err)
-   return err;
-   }
-
-   err = i915_active_acquire(>active);
-   if (err)
-   return err;
-
-   if (mutex_lock_interruptible(>pin_mutex)) {
-   err = -EINTR;
-   goto out_release;
-   }
-
-   if (unlikely(intel_context_is_closed(ce))) {
-   err = -ENOENT;
-   goto out_unlock;
-   }
-
-   if (likely(!atomic_add_unless(>pin_count, 1, 0))) {
-   err = intel_context_active_acquire(ce);
-   if (unlikely(err))
-   goto out_unlock;
-
-   err = ce->ops->pin(ce);
-   if (unlikely(err))
-   goto err_active;
-
-   CE_TRACE(ce, "pin ring:{start:%08x, head:%04x, tail:%04x}\n",
-i915_ggtt_offset(ce->ring->vma),
-ce->ring->head, ce->ring->tail);
-
-   smp_mb__before_atomic(); /* flush pin before it is visible */
-   atomic_inc(>pin_count);
-   }
-
-   GEM_BUG_ON(!intel_context_is_pinned(ce)); /* no overflow! */
-   GEM_BUG_ON(i915_active_is_idle(>active));
-   goto out_unlock;
-
-err_active:
-   intel_context_active_release(ce);
-out_unlock:
-   mutex_unlock(>pin_mutex);
-out_release:
-   i915_active_release(>active);
-   return err;
-}
-
-void intel_context_unpin(struct intel_context *ce)
-{
-   if (!atomic_dec_and_test(>pin_count))
-   return;
-
-   CE_TRACE(ce, "unpin\n");
-   ce->ops->unpin(ce);
-
-   /*
-* Once released, we may asynchronously drop the active reference.
-* As that may be the only reference keeping the context alive,
-* take an extra now so that it is not freed before we finish
-* dereferencing it.
-*/
-   intel_context_get(ce);
-   intel_context_active_release(ce);
-   intel_context_put(ce);
-}
-
 static int __context_pin_state(struct i915_vma *vma)
 {
unsigned int bias = i915_ggtt_pin_bias(vma) | PIN_OFFSET_BIAS;
@@ -225,6 +152,138 @@ static void __ring_retire(struct intel_ring *ring)
i915_active_release(>vma->active);
 }
 
+static int intel_context_pre_pin(struct intel_context *ce)
+{
+   int err;
+
+   CE_TRACE(ce, "active\n");
+
+   err = __ring_active(ce->ring);
+   if (err)
+   return err;
+
+   err = intel_timeline_pin(ce->timeline);
+   if (err)
+   goto err_ring;
+
+   if (!ce->state)
+   return 0;
+
+   err = __context_pin_state(ce->state);
+   if (err)
+   goto err_timeline;
+
+
+   return 0;
+
+err_timeline:
+   intel_timeline_unpin(ce->timeline);
+err_ring:
+   __ring_retire(ce->ring);
+   return err;
+}
+
+static void intel_context_post_unpin(struct intel_context *ce)
+{
+   if (ce->state)
+   __context_unpin_state(ce->state);
+
+   intel_timeline_unpin(ce->timeline);
+   __ring_retire(ce->ring);
+}
+
+int __intel_context_do_pin(struct intel_context *ce)
+{
+   bool handoff = false;
+   void *vaddr;
+   int err = 0;
+
+   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
+   err = intel_context_alloc_state(ce);
+   if (err)
+   return err;
+   }
+
+   /*
+* We always pin the context/ring/timeline here, to ensure a pin
+* refcount for __intel_context_active(), which prevent a lock
+* inversion of ce->pin_mutex vs dma_resv_lock().
+*/
+   err = intel_context_pre_pin(ce);
+   if (err)
+   return err;
+
+   err = i915_active_acquire(>active);
+   

[Intel-gfx] [PATCH 12/23] drm/i915: Rework intel_context pinning to do everything outside of pin_mutex

2020-04-02 Thread Maarten Lankhorst
Instead of doing everything inside of pin_mutex, we move all pinning
outside. Because i915_active has its own reference counting and
pinning is also having the same issues vs mutexes, we make sure
everything is pinned first, so the pinning in i915_active only needs
to bump refcounts. This allows us to take pin refcounts correctly
all the time.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/i915/gt/intel_context.c   | 233 +++---
 drivers/gpu/drm/i915/gt/intel_context_types.h |   4 +-
 drivers/gpu/drm/i915/gt/intel_lrc.c   |  34 ++-
 drivers/gpu/drm/i915/gt/intel_renderstate.c   |   1 -
 .../gpu/drm/i915/gt/intel_ring_submission.c   |  13 +-
 drivers/gpu/drm/i915/gt/mock_engine.c |  13 +-
 6 files changed, 191 insertions(+), 107 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
b/drivers/gpu/drm/i915/gt/intel_context.c
index e4aece20bc80..bc0ed268ccb8 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -93,79 +93,6 @@ static void intel_context_active_release(struct 
intel_context *ce)
i915_active_release(>active);
 }
 
-int __intel_context_do_pin(struct intel_context *ce)
-{
-   int err;
-
-   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
-   err = intel_context_alloc_state(ce);
-   if (err)
-   return err;
-   }
-
-   err = i915_active_acquire(>active);
-   if (err)
-   return err;
-
-   if (mutex_lock_interruptible(>pin_mutex)) {
-   err = -EINTR;
-   goto out_release;
-   }
-
-   if (unlikely(intel_context_is_closed(ce))) {
-   err = -ENOENT;
-   goto out_unlock;
-   }
-
-   if (likely(!atomic_add_unless(>pin_count, 1, 0))) {
-   err = intel_context_active_acquire(ce);
-   if (unlikely(err))
-   goto out_unlock;
-
-   err = ce->ops->pin(ce);
-   if (unlikely(err))
-   goto err_active;
-
-   CE_TRACE(ce, "pin ring:{start:%08x, head:%04x, tail:%04x}\n",
-i915_ggtt_offset(ce->ring->vma),
-ce->ring->head, ce->ring->tail);
-
-   smp_mb__before_atomic(); /* flush pin before it is visible */
-   atomic_inc(>pin_count);
-   }
-
-   GEM_BUG_ON(!intel_context_is_pinned(ce)); /* no overflow! */
-   GEM_BUG_ON(i915_active_is_idle(>active));
-   goto out_unlock;
-
-err_active:
-   intel_context_active_release(ce);
-out_unlock:
-   mutex_unlock(>pin_mutex);
-out_release:
-   i915_active_release(>active);
-   return err;
-}
-
-void intel_context_unpin(struct intel_context *ce)
-{
-   if (!atomic_dec_and_test(>pin_count))
-   return;
-
-   CE_TRACE(ce, "unpin\n");
-   ce->ops->unpin(ce);
-
-   /*
-* Once released, we may asynchronously drop the active reference.
-* As that may be the only reference keeping the context alive,
-* take an extra now so that it is not freed before we finish
-* dereferencing it.
-*/
-   intel_context_get(ce);
-   intel_context_active_release(ce);
-   intel_context_put(ce);
-}
-
 static int __context_pin_state(struct i915_vma *vma)
 {
unsigned int bias = i915_ggtt_pin_bias(vma) | PIN_OFFSET_BIAS;
@@ -225,6 +152,138 @@ static void __ring_retire(struct intel_ring *ring)
i915_active_release(>vma->active);
 }
 
+static int intel_context_pre_pin(struct intel_context *ce)
+{
+   int err;
+
+   CE_TRACE(ce, "active\n");
+
+   err = __ring_active(ce->ring);
+   if (err)
+   return err;
+
+   err = intel_timeline_pin(ce->timeline);
+   if (err)
+   goto err_ring;
+
+   if (!ce->state)
+   return 0;
+
+   err = __context_pin_state(ce->state);
+   if (err)
+   goto err_timeline;
+
+
+   return 0;
+
+err_timeline:
+   intel_timeline_unpin(ce->timeline);
+err_ring:
+   __ring_retire(ce->ring);
+   return err;
+}
+
+static void intel_context_post_unpin(struct intel_context *ce)
+{
+   if (ce->state)
+   __context_unpin_state(ce->state);
+
+   intel_timeline_unpin(ce->timeline);
+   __ring_retire(ce->ring);
+}
+
+int __intel_context_do_pin(struct intel_context *ce)
+{
+   bool handoff = false;
+   void *vaddr;
+   int err = 0;
+
+   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
+   err = intel_context_alloc_state(ce);
+   if (err)
+   return err;
+   }
+
+   /*
+* We always pin the context/ring/timeline here, to ensure a pin
+* refcount for __intel_context_active(), which prevent a lock
+* inversion of ce->pin_mutex vs dma_resv_lock().
+*/
+   err = intel_context_pre_pin(ce);
+   if (err)
+   return 

[Intel-gfx] [PATCH 12/23] drm/i915: Rework intel_context pinning to do everything outside of pin_mutex

2020-03-31 Thread Maarten Lankhorst
Instead of doing everything inside of pin_mutex, we move all pinning
outside. Because i915_active has its own reference counting and
pinning is also having the same issues vs mutexes, we make sure
everything is pinned first, so the pinning in i915_active only needs
to bump refcounts. This allows us to take pin refcounts correctly
all the time.

Signed-off-by: Maarten Lankhorst 
---
 drivers/gpu/drm/i915/gt/intel_context.c   | 233 +++---
 drivers/gpu/drm/i915/gt/intel_context_types.h |   4 +-
 drivers/gpu/drm/i915/gt/intel_lrc.c   |  34 ++-
 drivers/gpu/drm/i915/gt/intel_renderstate.c   |   1 -
 .../gpu/drm/i915/gt/intel_ring_submission.c   |  13 +-
 drivers/gpu/drm/i915/gt/mock_engine.c |  13 +-
 6 files changed, 191 insertions(+), 107 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/intel_context.c 
b/drivers/gpu/drm/i915/gt/intel_context.c
index e4aece20bc80..bc0ed268ccb8 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -93,79 +93,6 @@ static void intel_context_active_release(struct 
intel_context *ce)
i915_active_release(>active);
 }
 
-int __intel_context_do_pin(struct intel_context *ce)
-{
-   int err;
-
-   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
-   err = intel_context_alloc_state(ce);
-   if (err)
-   return err;
-   }
-
-   err = i915_active_acquire(>active);
-   if (err)
-   return err;
-
-   if (mutex_lock_interruptible(>pin_mutex)) {
-   err = -EINTR;
-   goto out_release;
-   }
-
-   if (unlikely(intel_context_is_closed(ce))) {
-   err = -ENOENT;
-   goto out_unlock;
-   }
-
-   if (likely(!atomic_add_unless(>pin_count, 1, 0))) {
-   err = intel_context_active_acquire(ce);
-   if (unlikely(err))
-   goto out_unlock;
-
-   err = ce->ops->pin(ce);
-   if (unlikely(err))
-   goto err_active;
-
-   CE_TRACE(ce, "pin ring:{start:%08x, head:%04x, tail:%04x}\n",
-i915_ggtt_offset(ce->ring->vma),
-ce->ring->head, ce->ring->tail);
-
-   smp_mb__before_atomic(); /* flush pin before it is visible */
-   atomic_inc(>pin_count);
-   }
-
-   GEM_BUG_ON(!intel_context_is_pinned(ce)); /* no overflow! */
-   GEM_BUG_ON(i915_active_is_idle(>active));
-   goto out_unlock;
-
-err_active:
-   intel_context_active_release(ce);
-out_unlock:
-   mutex_unlock(>pin_mutex);
-out_release:
-   i915_active_release(>active);
-   return err;
-}
-
-void intel_context_unpin(struct intel_context *ce)
-{
-   if (!atomic_dec_and_test(>pin_count))
-   return;
-
-   CE_TRACE(ce, "unpin\n");
-   ce->ops->unpin(ce);
-
-   /*
-* Once released, we may asynchronously drop the active reference.
-* As that may be the only reference keeping the context alive,
-* take an extra now so that it is not freed before we finish
-* dereferencing it.
-*/
-   intel_context_get(ce);
-   intel_context_active_release(ce);
-   intel_context_put(ce);
-}
-
 static int __context_pin_state(struct i915_vma *vma)
 {
unsigned int bias = i915_ggtt_pin_bias(vma) | PIN_OFFSET_BIAS;
@@ -225,6 +152,138 @@ static void __ring_retire(struct intel_ring *ring)
i915_active_release(>vma->active);
 }
 
+static int intel_context_pre_pin(struct intel_context *ce)
+{
+   int err;
+
+   CE_TRACE(ce, "active\n");
+
+   err = __ring_active(ce->ring);
+   if (err)
+   return err;
+
+   err = intel_timeline_pin(ce->timeline);
+   if (err)
+   goto err_ring;
+
+   if (!ce->state)
+   return 0;
+
+   err = __context_pin_state(ce->state);
+   if (err)
+   goto err_timeline;
+
+
+   return 0;
+
+err_timeline:
+   intel_timeline_unpin(ce->timeline);
+err_ring:
+   __ring_retire(ce->ring);
+   return err;
+}
+
+static void intel_context_post_unpin(struct intel_context *ce)
+{
+   if (ce->state)
+   __context_unpin_state(ce->state);
+
+   intel_timeline_unpin(ce->timeline);
+   __ring_retire(ce->ring);
+}
+
+int __intel_context_do_pin(struct intel_context *ce)
+{
+   bool handoff = false;
+   void *vaddr;
+   int err = 0;
+
+   if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, >flags))) {
+   err = intel_context_alloc_state(ce);
+   if (err)
+   return err;
+   }
+
+   /*
+* We always pin the context/ring/timeline here, to ensure a pin
+* refcount for __intel_context_active(), which prevent a lock
+* inversion of ce->pin_mutex vs dma_resv_lock().
+*/
+   err = intel_context_pre_pin(ce);
+   if (err)
+   return