]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - drivers/gpu/drm/i915/intel_ringbuffer.h
Merge tag 'drm-intel-next-2017-12-01' of git://anongit.freedesktop.org/drm/drm-intel...
[thirdparty/linux.git] / drivers / gpu / drm / i915 / intel_ringbuffer.h
index f867aa6c31fca936e7aa71f773fe58defd98b749..c68ab3ead83cef95ec9a6fa89de3b714f101ac9d 100644 (file)
@@ -6,6 +6,7 @@
 #include "i915_gem_batch_pool.h"
 #include "i915_gem_request.h"
 #include "i915_gem_timeline.h"
+#include "i915_pmu.h"
 #include "i915_selftest.h"
 
 struct drm_printer;
@@ -47,16 +48,6 @@ struct intel_hw_status_page {
 /* seqno size is actually only a uint32, but since we plan to use MI_FLUSH_DW to
  * do the writes, and that must have qw aligned offsets, simply pretend it's 8b.
  */
-#define gen8_semaphore_seqno_size sizeof(uint64_t)
-#define GEN8_SEMAPHORE_OFFSET(__from, __to)                         \
-       (((__from) * I915_NUM_ENGINES  + (__to)) * gen8_semaphore_seqno_size)
-#define GEN8_SIGNAL_OFFSET(__ring, to)                      \
-       (dev_priv->semaphore->node.start + \
-        GEN8_SEMAPHORE_OFFSET((__ring)->id, (to)))
-#define GEN8_WAIT_OFFSET(__ring, from)                      \
-       (dev_priv->semaphore->node.start + \
-        GEN8_SEMAPHORE_OFFSET(from, (__ring)->id))
-
 enum intel_engine_hangcheck_action {
        ENGINE_IDLE = 0,
        ENGINE_WAIT,
@@ -252,6 +243,7 @@ struct intel_engine_execlists {
        unsigned int active;
 #define EXECLISTS_ACTIVE_USER 0
 #define EXECLISTS_ACTIVE_PREEMPT 1
+#define EXECLISTS_ACTIVE_HWACK 2
 
        /**
         * @port_mask: number of execlist ports - 1
@@ -348,6 +340,43 @@ struct intel_engine_cs {
                I915_SELFTEST_DECLARE(bool mock : 1);
        } breadcrumbs;
 
+       struct {
+               /**
+                * @enable: Bitmask of enable sample events on this engine.
+                *
+                * Bits correspond to sample event types, for instance
+                * I915_SAMPLE_QUEUED is bit 0 etc.
+                */
+               u32 enable;
+               /**
+                * @enable_count: Reference count for the enabled samplers.
+                *
+                * Index number corresponds to the bit number from @enable.
+                */
+               unsigned int enable_count[I915_PMU_SAMPLE_BITS];
+               /**
+                * @sample: Counter values for sampling events.
+                *
+                * Our internal timer stores the current counters in this field.
+                */
+#define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1)
+               struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX];
+               /**
+                * @busy_stats: Has enablement of engine stats tracking been
+                *              requested.
+                */
+               bool busy_stats;
+               /**
+                * @disable_busy_stats: Work item for busy stats disabling.
+                *
+                * Same as with @enable_busy_stats action, with the difference
+                * that we delay it in case there are rapid enable-disable
+                * actions, which can happen during tool startup (like perf
+                * stat).
+                */
+               struct delayed_work disable_busy_stats;
+       } pmu;
+
        /*
         * A pool of objects to use as shadow copies of client batch buffers
         * when the command parser is enabled. Prevents the client from
@@ -467,18 +496,15 @@ struct intel_engine_cs {
         *  ie. transpose of f(x, y)
         */
        struct {
-               union {
 #define GEN6_SEMAPHORE_LAST    VECS_HW
 #define GEN6_NUM_SEMAPHORES    (GEN6_SEMAPHORE_LAST + 1)
 #define GEN6_SEMAPHORES_MASK   GENMASK(GEN6_SEMAPHORE_LAST, 0)
-                       struct {
-                               /* our mbox written by others */
-                               u32             wait[GEN6_NUM_SEMAPHORES];
-                               /* mboxes this ring signals to */
-                               i915_reg_t      signal[GEN6_NUM_SEMAPHORES];
-                       } mbox;
-                       u64             signal_ggtt[I915_NUM_ENGINES];
-               };
+               struct {
+                       /* our mbox written by others */
+                       u32             wait[GEN6_NUM_SEMAPHORES];
+                       /* mboxes this ring signals to */
+                       i915_reg_t      signal[GEN6_NUM_SEMAPHORES];
+               } mbox;
 
                /* AKA wait() */
                int     (*sync_to)(struct drm_i915_gem_request *req,
@@ -506,13 +532,16 @@ struct intel_engine_cs {
         * stream (ring).
         */
        struct i915_gem_context *legacy_active_context;
+       struct i915_hw_ppgtt *legacy_active_ppgtt;
 
        /* status_notifier: list of callbacks for context-switch changes */
        struct atomic_notifier_head context_status_notifier;
 
        struct intel_engine_hangcheck hangcheck;
 
-       bool needs_cmd_parser;
+#define I915_ENGINE_NEEDS_CMD_PARSER BIT(0)
+#define I915_ENGINE_SUPPORTS_STATS   BIT(1)
+       unsigned int flags;
 
        /*
         * Table of commands the command parser needs to know about
@@ -537,8 +566,50 @@ struct intel_engine_cs {
         * certain bits to encode the command length in the header).
         */
        u32 (*get_cmd_length_mask)(u32 cmd_header);
+
+       struct {
+               /**
+                * @lock: Lock protecting the below fields.
+                */
+               spinlock_t lock;
+               /**
+                * @enabled: Reference count indicating number of listeners.
+                */
+               unsigned int enabled;
+               /**
+                * @active: Number of contexts currently scheduled in.
+                */
+               unsigned int active;
+               /**
+                * @enabled_at: Timestamp when busy stats were enabled.
+                */
+               ktime_t enabled_at;
+               /**
+                * @start: Timestamp of the last idle to active transition.
+                *
+                * Idle is defined as active == 0, active is active > 0.
+                */
+               ktime_t start;
+               /**
+                * @total: Total time this engine was busy.
+                *
+                * Accumulated time not counting the most recent block in cases
+                * where engine is currently busy (active > 0).
+                */
+               ktime_t total;
+       } stats;
 };
 
+static inline bool intel_engine_needs_cmd_parser(struct intel_engine_cs *engine)
+{
+       return engine->flags & I915_ENGINE_NEEDS_CMD_PARSER;
+}
+
+static inline bool intel_engine_supports_stats(struct intel_engine_cs *engine)
+{
+       return engine->flags & I915_ENGINE_SUPPORTS_STATS;
+}
+
 static inline void
 execlists_set_active(struct intel_engine_execlists *execlists,
                     unsigned int bit)
@@ -939,4 +1010,67 @@ bool intel_engine_can_store_dword(struct intel_engine_cs *engine);
 
 void intel_engine_dump(struct intel_engine_cs *engine, struct drm_printer *p);
 
+struct intel_engine_cs *
+intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance);
+
+static inline void intel_engine_context_in(struct intel_engine_cs *engine)
+{
+       unsigned long flags;
+
+       if (READ_ONCE(engine->stats.enabled) == 0)
+               return;
+
+       spin_lock_irqsave(&engine->stats.lock, flags);
+
+       if (engine->stats.enabled > 0) {
+               if (engine->stats.active++ == 0)
+                       engine->stats.start = ktime_get();
+               GEM_BUG_ON(engine->stats.active == 0);
+       }
+
+       spin_unlock_irqrestore(&engine->stats.lock, flags);
+}
+
+static inline void intel_engine_context_out(struct intel_engine_cs *engine)
+{
+       unsigned long flags;
+
+       if (READ_ONCE(engine->stats.enabled) == 0)
+               return;
+
+       spin_lock_irqsave(&engine->stats.lock, flags);
+
+       if (engine->stats.enabled > 0) {
+               ktime_t last;
+
+               if (engine->stats.active && --engine->stats.active == 0) {
+                       /*
+                        * Decrement the active context count and in case GPU
+                        * is now idle add up to the running total.
+                        */
+                       last = ktime_sub(ktime_get(), engine->stats.start);
+
+                       engine->stats.total = ktime_add(engine->stats.total,
+                                                       last);
+               } else if (engine->stats.active == 0) {
+                       /*
+                        * After turning on engine stats, context out might be
+                        * the first event in which case we account from the
+                        * time stats gathering was turned on.
+                        */
+                       last = ktime_sub(ktime_get(), engine->stats.enabled_at);
+
+                       engine->stats.total = ktime_add(engine->stats.total,
+                                                       last);
+               }
+       }
+
+       spin_unlock_irqrestore(&engine->stats.lock, flags);
+}
+
+int intel_enable_engine_stats(struct intel_engine_cs *engine);
+void intel_disable_engine_stats(struct intel_engine_cs *engine);
+
+ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine);
+
 #endif /* _INTEL_RINGBUFFER_H_ */