The principal motivation for this was to try and eliminate the
struct_mutex from i915_gem_suspend - but we still need to hold the mutex
current for the i915_gem_context_lost(). (The issue there is that there
may be an indirect lockdep cycle between cpu_hotplug (i.e. suspend) and
struct_mutex via the stop_machine().) For the moment, enabling last
request tracking for the engine, allows us to do busyness checking and
waiting without requiring the struct_mutex - which is useful in its own
right.

Signed-off-by: Chris Wilson <[email protected]>
---
 drivers/gpu/drm/i915/i915_gem.c         | 37 ++++++++++-----------------------
 drivers/gpu/drm/i915/i915_gem_evict.c   |  2 +-
 drivers/gpu/drm/i915/i915_gem_request.c |  5 +++--
 drivers/gpu/drm/i915/i915_gem_request.h | 11 ++++++++++
 drivers/gpu/drm/i915/i915_gpu_error.c   |  2 +-
 drivers/gpu/drm/i915/i915_irq.c         |  3 +--
 drivers/gpu/drm/i915/intel_engine_cs.c  |  8 ++++++-
 drivers/gpu/drm/i915/intel_pm.c         |  2 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c | 16 +++-----------
 drivers/gpu/drm/i915/intel_ringbuffer.h | 24 +++++++++++----------
 10 files changed, 52 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f164ad482bdc..8ac9605d5125 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2432,13 +2432,18 @@ static void i915_gem_reset_engine_status(struct 
intel_engine_cs *engine)
 
 static void i915_gem_reset_engine_cleanup(struct intel_engine_cs *engine)
 {
+       struct drm_i915_gem_request *request;
        struct intel_ring *ring;
 
+       request = i915_gem_active_peek(&engine->last_request,
+                                      &engine->i915->drm.struct_mutex);
+
        /* Mark all pending requests as complete so that any concurrent
         * (lockless) lookup doesn't try and wait upon the request as we
         * reset it.
         */
-       intel_engine_init_seqno(engine, engine->last_submitted_seqno);
+       if (request)
+               intel_engine_init_seqno(engine, request->fence.seqno);
 
        /*
         * Clear the execlists queue up before freeing the requests, as those
@@ -2460,15 +2465,9 @@ static void i915_gem_reset_engine_cleanup(struct 
intel_engine_cs *engine)
         * implicit references on things like e.g. ppgtt address spaces through
         * the request.
         */
-       if (!list_empty(&engine->request_list)) {
-               struct drm_i915_gem_request *request;
-
-               request = list_last_entry(&engine->request_list,
-                                         struct drm_i915_gem_request,
-                                         link);
-
+       if (request)
                i915_gem_request_retire_upto(request);
-       }
+       GEM_BUG_ON(intel_engine_is_active(engine));
 
        /* Having flushed all requests from all queues, we know that all
         * ringbuffers must now be empty. However, since we do not reclaim
@@ -2896,8 +2895,6 @@ int i915_gem_wait_for_idle(struct drm_i915_private 
*dev_priv)
        struct intel_engine_cs *engine;
        int ret;
 
-       lockdep_assert_held(&dev_priv->drm.struct_mutex);
-
        for_each_engine(engine, dev_priv) {
                if (engine->last_context == NULL)
                        continue;
@@ -4069,21 +4066,10 @@ struct i915_vma *i915_gem_obj_to_ggtt_view(struct 
drm_i915_gem_object *obj,
        return NULL;
 }
 
-static void
-i915_gem_stop_engines(struct drm_device *dev)
+int i915_gem_suspend(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct intel_engine_cs *engine;
-
-       for_each_engine(engine, dev_priv)
-               dev_priv->gt.stop_engine(engine);
-}
-
-int
-i915_gem_suspend(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       int ret = 0;
+       int ret;
 
        intel_suspend_gt_powersave(dev_priv);
 
@@ -4112,7 +4098,6 @@ i915_gem_suspend(struct drm_device *dev)
         * and similar for all logical context images (to ensure they are
         * all ready for hibernation).
         */
-       i915_gem_stop_engines(dev);
        i915_gem_context_lost(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
@@ -4128,7 +4113,7 @@ i915_gem_suspend(struct drm_device *dev)
        return 0;
 
 err:
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev_priv->drm.struct_mutex);
        return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c 
b/drivers/gpu/drm/i915/i915_gem_evict.c
index 7be425826539..624c0f016c84 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -39,7 +39,7 @@ gpu_is_idle(struct drm_i915_private *dev_priv)
        struct intel_engine_cs *engine;
 
        for_each_engine(engine, dev_priv) {
-               if (!list_empty(&engine->request_list))
+               if (intel_engine_is_active(engine))
                        return false;
        }
 
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c 
b/drivers/gpu/drm/i915/i915_gem_request.c
index 3fecb8f0e041..8289d31c0ef5 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -486,7 +486,8 @@ void __i915_add_request(struct drm_i915_gem_request 
*request,
         */
        request->emitted_jiffies = jiffies;
        request->previous_seqno = engine->last_submitted_seqno;
-       smp_store_mb(engine->last_submitted_seqno, request->fence.seqno);
+       engine->last_submitted_seqno = request->fence.seqno;
+       i915_gem_active_set(&engine->last_request, request);
        list_add_tail(&request->link, &engine->request_list);
        list_add_tail(&request->ring_link, &ring->request_list);
 
@@ -757,7 +758,7 @@ void i915_gem_retire_requests(struct drm_i915_private 
*dev_priv)
 
        for_each_engine(engine, dev_priv) {
                engine_retire_requests(engine);
-               if (list_empty(&engine->request_list))
+               if (!intel_engine_is_active(engine))
                        dev_priv->gt.active_engines &= 
~intel_engine_flag(engine);
        }
 
diff --git a/drivers/gpu/drm/i915/i915_gem_request.h 
b/drivers/gpu/drm/i915/i915_gem_request.h
index d077b023a89f..3d7c63dec5b3 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.h
+++ b/drivers/gpu/drm/i915/i915_gem_request.h
@@ -29,6 +29,17 @@
 
 #include "i915_gem.h"
 
+struct intel_wait {
+       struct rb_node node;
+       struct task_struct *tsk;
+       u32 seqno;
+};
+
+struct intel_signal_node {
+       struct rb_node node;
+       struct intel_wait wait;
+};
+
 /**
  * Request queue structure.
  *
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c 
b/drivers/gpu/drm/i915/i915_gpu_error.c
index cc28ad429dd8..0edae7d0207d 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -1002,7 +1002,7 @@ static void error_record_engine_registers(struct 
drm_i915_error_state *error,
        ee->instpm = I915_READ(RING_INSTPM(engine->mmio_base));
        ee->acthd = intel_engine_get_active_head(engine);
        ee->seqno = intel_engine_get_seqno(engine);
-       ee->last_seqno = engine->last_submitted_seqno;
+       ee->last_seqno = __active_get_seqno(&engine->last_request);
        ee->start = I915_READ_START(engine);
        ee->head = I915_READ_HEAD(engine);
        ee->tail = I915_READ_TAIL(engine);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index e58650096426..e35af9ba1546 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -2807,8 +2807,7 @@ static void gen8_disable_vblank(struct drm_device *dev, 
unsigned int pipe)
 static bool
 ring_idle(struct intel_engine_cs *engine, u32 seqno)
 {
-       return i915_seqno_passed(seqno,
-                                READ_ONCE(engine->last_submitted_seqno));
+       return !intel_engine_is_active(engine);
 }
 
 static bool
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c 
b/drivers/gpu/drm/i915/intel_engine_cs.c
index 6665068e583c..b2bcd468028d 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -166,6 +166,12 @@ void intel_engine_init_hangcheck(struct intel_engine_cs 
*engine)
        memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
 }
 
+static void intel_engine_init_requests(struct intel_engine_cs *engine)
+{
+       init_request_active(&engine->last_request, NULL);
+       INIT_LIST_HEAD(&engine->request_list);
+}
+
 /**
  * intel_engines_setup_common - setup engine state not requiring hw access
  * @engine: Engine to setup.
@@ -177,13 +183,13 @@ void intel_engine_init_hangcheck(struct intel_engine_cs 
*engine)
  */
 void intel_engine_setup_common(struct intel_engine_cs *engine)
 {
-       INIT_LIST_HEAD(&engine->request_list);
        INIT_LIST_HEAD(&engine->buffers);
        INIT_LIST_HEAD(&engine->execlist_queue);
        spin_lock_init(&engine->execlist_lock);
 
        engine->fence_context = fence_context_alloc(1);
 
+       intel_engine_init_requests(engine);
        intel_engine_init_hangcheck(engine);
        i915_gem_batch_pool_init(engine, &engine->batch_pool);
 }
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 1ac32428d4db..d8a41c7acb3d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -6328,7 +6328,7 @@ bool i915_gpu_busy(void)
        dev_priv = i915_mch_dev;
 
        for_each_engine(engine, dev_priv)
-               ret |= !list_empty(&engine->request_list);
+               ret |= intel_engine_is_active(engine);
 
 out_unlock:
        spin_unlock_irq(&mchdev_lock);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c 
b/drivers/gpu/drm/i915/intel_ringbuffer.c
index cb1131d3a9d0..7f6633b03916 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -2232,20 +2232,10 @@ void intel_engine_cleanup(struct intel_engine_cs 
*engine)
 
 int intel_engine_idle(struct intel_engine_cs *engine)
 {
-       struct drm_i915_gem_request *req;
-
        /* Wait upon the last request to be completed */
-       if (list_empty(&engine->request_list))
-               return 0;
-
-       req = list_entry(engine->request_list.prev,
-                        struct drm_i915_gem_request,
-                        link);
-
-       /* Make sure we do not trigger any retires */
-       return i915_wait_request(req,
-                                req->i915->mm.interruptible,
-                                NULL, NULL);
+       return i915_gem_active_wait_unlocked(&engine->last_request,
+                                            engine->i915->mm.interruptible,
+                                            NULL, NULL);
 }
 
 int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h 
b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 6c240356cccb..903c06ef6fff 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -3,6 +3,7 @@
 
 #include <linux/hashtable.h>
 #include "i915_gem_batch_pool.h"
+#include "i915_gem_request.h"
 
 #define I915_CMD_HASH_ORDER 9
 
@@ -307,6 +308,13 @@ struct intel_engine_cs {
         */
        u32 last_submitted_seqno;
 
+       /* An RCU guarded pointer to the last request. No reference is
+        * held to the request, users must carefully acquire a reference to
+        * the request using i915_gem_active_get_request_rcu(), or hold the
+        * struct_mutex.
+        */
+       struct i915_gem_active last_request;
+
        struct i915_gem_context *last_context;
 
        struct intel_engine_hangcheck hangcheck;
@@ -503,17 +511,6 @@ static inline u32 intel_hws_seqno_address(struct 
intel_engine_cs *engine)
 }
 
 /* intel_breadcrumbs.c -- user interrupt bottom-half for waiters */
-struct intel_wait {
-       struct rb_node node;
-       struct task_struct *tsk;
-       u32 seqno;
-};
-
-struct intel_signal_node {
-       struct rb_node node;
-       struct intel_wait wait;
-};
-
 int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
 
 static inline void intel_wait_init(struct intel_wait *wait, u32 seqno)
@@ -560,4 +557,9 @@ void intel_engine_fini_breadcrumbs(struct intel_engine_cs 
*engine);
 unsigned int intel_kick_waiters(struct drm_i915_private *i915);
 unsigned int intel_kick_signalers(struct drm_i915_private *i915);
 
+static inline bool intel_engine_is_active(struct intel_engine_cs *engine)
+{
+       return __i915_gem_active_is_busy(&engine->last_request);
+}
+
 #endif /* _INTEL_RINGBUFFER_H_ */
-- 
2.8.1

_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to