]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/intel_engine_cs.c
drm/i915: Move the global sync optimisation to the timeline
[karo-tx-linux.git] / drivers / gpu / drm / i915 / intel_engine_cs.c
index e405f1080296131a71b452e9fb738410239a8a84..94de3d66733dd45524ff79b6361ff51866b66502 100644 (file)
@@ -82,12 +82,17 @@ static const struct engine_info {
        },
 };
 
-static struct intel_engine_cs *
+static int
 intel_engine_setup(struct drm_i915_private *dev_priv,
                   enum intel_engine_id id)
 {
        const struct engine_info *info = &intel_engines[id];
-       struct intel_engine_cs *engine = &dev_priv->engine[id];
+       struct intel_engine_cs *engine;
+
+       GEM_BUG_ON(dev_priv->engine[id]);
+       engine = kzalloc(sizeof(*engine), GFP_KERNEL);
+       if (!engine)
+               return -ENOMEM;
 
        engine->id = id;
        engine->i915 = dev_priv;
@@ -97,7 +102,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
        engine->mmio_base = info->mmio_base;
        engine->irq_shift = info->irq_shift;
 
-       return engine;
+       dev_priv->engine[id] = engine;
+       return 0;
 }
 
 /**
@@ -110,13 +116,16 @@ int intel_engines_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_device_info *device_info = mkwrite_device_info(dev_priv);
+       unsigned int ring_mask = INTEL_INFO(dev_priv)->ring_mask;
        unsigned int mask = 0;
        int (*init)(struct intel_engine_cs *engine);
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
        unsigned int i;
        int ret;
 
-       WARN_ON(INTEL_INFO(dev_priv)->ring_mask == 0);
-       WARN_ON(INTEL_INFO(dev_priv)->ring_mask &
+       WARN_ON(ring_mask == 0);
+       WARN_ON(ring_mask &
                GENMASK(sizeof(mask) * BITS_PER_BYTE - 1, I915_NUM_ENGINES));
 
        for (i = 0; i < ARRAY_SIZE(intel_engines); i++) {
@@ -131,7 +140,11 @@ int intel_engines_init(struct drm_device *dev)
                if (!init)
                        continue;
 
-               ret = init(intel_engine_setup(dev_priv, i));
+               ret = intel_engine_setup(dev_priv, i);
+               if (ret)
+                       goto cleanup;
+
+               ret = init(dev_priv->engine[i]);
                if (ret)
                        goto cleanup;
 
@@ -143,7 +156,7 @@ int intel_engines_init(struct drm_device *dev)
         * are added to the driver by a warning and disabling the forgotten
         * engines.
         */
-       if (WARN_ON(mask != INTEL_INFO(dev_priv)->ring_mask))
+       if (WARN_ON(mask != ring_mask))
                device_info->ring_mask = mask;
 
        device_info->num_rings = hweight32(mask);
@@ -151,17 +164,17 @@ int intel_engines_init(struct drm_device *dev)
        return 0;
 
 cleanup:
-       for (i = 0; i < I915_NUM_ENGINES; i++) {
+       for_each_engine(engine, dev_priv, id) {
                if (i915.enable_execlists)
-                       intel_logical_ring_cleanup(&dev_priv->engine[i]);
+                       intel_logical_ring_cleanup(engine);
                else
-                       intel_engine_cleanup(&dev_priv->engine[i]);
+                       intel_engine_cleanup(engine);
        }
 
        return ret;
 }
 
-void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno)
+void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno)
 {
        struct drm_i915_private *dev_priv = engine->i915;
 
@@ -191,13 +204,13 @@ void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno)
                                       I915_NUM_ENGINES * gen8_semaphore_seqno_size);
                kunmap(page);
        }
-       memset(engine->semaphore.sync_seqno, 0,
-              sizeof(engine->semaphore.sync_seqno));
 
        intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
        if (engine->irq_seqno_barrier)
                engine->irq_seqno_barrier(engine);
-       engine->last_submitted_seqno = seqno;
+
+       GEM_BUG_ON(i915_gem_active_isset(&engine->timeline->last_request));
+       engine->timeline->last_submitted_seqno = seqno;
 
        engine->hangcheck.seqno = seqno;
 
@@ -210,15 +223,11 @@ void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno)
 void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
 {
        memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
-       clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
-       if (intel_engine_has_waiter(engine))
-               i915_queue_hangcheck(engine->i915);
 }
 
-static void intel_engine_init_requests(struct intel_engine_cs *engine)
+static void intel_engine_init_timeline(struct intel_engine_cs *engine)
 {
-       init_request_active(&engine->last_request, NULL);
-       INIT_LIST_HEAD(&engine->request_list);
+       engine->timeline = &engine->i915->gt.global_timeline.engine[engine->id];
 }
 
 /**
@@ -235,9 +244,7 @@ void intel_engine_setup_common(struct intel_engine_cs *engine)
        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_timeline(engine);
        intel_engine_init_hangcheck(engine);
        i915_gem_batch_pool_init(engine, &engine->batch_pool);
 
@@ -254,7 +261,7 @@ int intel_engine_create_scratch(struct intel_engine_cs *engine, int size)
 
        obj = i915_gem_object_create_stolen(&engine->i915->drm, size);
        if (!obj)
-               obj = i915_gem_object_create(&engine->i915->drm, size);
+               obj = i915_gem_object_create_internal(engine->i915, size);
        if (IS_ERR(obj)) {
                DRM_ERROR("Failed to allocate scratch page\n");
                return PTR_ERR(obj);
@@ -304,19 +311,11 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
        if (ret)
                return ret;
 
-       return 0;
-}
-
-void intel_engine_reset_irq(struct intel_engine_cs *engine)
-{
-       struct drm_i915_private *dev_priv = engine->i915;
+       ret = i915_gem_render_state_init(engine);
+       if (ret)
+               return ret;
 
-       spin_lock_irq(&dev_priv->irq_lock);
-       if (intel_engine_has_waiter(engine))
-               engine->irq_enable(engine);
-       else
-               engine->irq_disable(engine);
-       spin_unlock_irq(&dev_priv->irq_lock);
+       return 0;
 }
 
 /**
@@ -330,7 +329,142 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
 {
        intel_engine_cleanup_scratch(engine);
 
+       i915_gem_render_state_fini(engine);
        intel_engine_fini_breadcrumbs(engine);
        intel_engine_cleanup_cmd_parser(engine);
        i915_gem_batch_pool_fini(&engine->batch_pool);
 }
+
+u64 intel_engine_get_active_head(struct intel_engine_cs *engine)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+       u64 acthd;
+
+       if (INTEL_GEN(dev_priv) >= 8)
+               acthd = I915_READ64_2x32(RING_ACTHD(engine->mmio_base),
+                                        RING_ACTHD_UDW(engine->mmio_base));
+       else if (INTEL_GEN(dev_priv) >= 4)
+               acthd = I915_READ(RING_ACTHD(engine->mmio_base));
+       else
+               acthd = I915_READ(ACTHD);
+
+       return acthd;
+}
+
+u64 intel_engine_get_last_batch_head(struct intel_engine_cs *engine)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+       u64 bbaddr;
+
+       if (INTEL_GEN(dev_priv) >= 8)
+               bbaddr = I915_READ64_2x32(RING_BBADDR(engine->mmio_base),
+                                         RING_BBADDR_UDW(engine->mmio_base));
+       else
+               bbaddr = I915_READ(RING_BBADDR(engine->mmio_base));
+
+       return bbaddr;
+}
+
+const char *i915_cache_level_str(struct drm_i915_private *i915, int type)
+{
+       switch (type) {
+       case I915_CACHE_NONE: return " uncached";
+       case I915_CACHE_LLC: return HAS_LLC(i915) ? " LLC" : " snooped";
+       case I915_CACHE_L3_LLC: return " L3+LLC";
+       case I915_CACHE_WT: return " WT";
+       default: return "";
+       }
+}
+
+static inline uint32_t
+read_subslice_reg(struct drm_i915_private *dev_priv, int slice,
+                 int subslice, i915_reg_t reg)
+{
+       uint32_t mcr;
+       uint32_t ret;
+       enum forcewake_domains fw_domains;
+
+       fw_domains = intel_uncore_forcewake_for_reg(dev_priv, reg,
+                                                   FW_REG_READ);
+       fw_domains |= intel_uncore_forcewake_for_reg(dev_priv,
+                                                    GEN8_MCR_SELECTOR,
+                                                    FW_REG_READ | FW_REG_WRITE);
+
+       spin_lock_irq(&dev_priv->uncore.lock);
+       intel_uncore_forcewake_get__locked(dev_priv, fw_domains);
+
+       mcr = I915_READ_FW(GEN8_MCR_SELECTOR);
+       /*
+        * The HW expects the slice and sublice selectors to be reset to 0
+        * after reading out the registers.
+        */
+       WARN_ON_ONCE(mcr & (GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK));
+       mcr &= ~(GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK);
+       mcr |= GEN8_MCR_SLICE(slice) | GEN8_MCR_SUBSLICE(subslice);
+       I915_WRITE_FW(GEN8_MCR_SELECTOR, mcr);
+
+       ret = I915_READ_FW(reg);
+
+       mcr &= ~(GEN8_MCR_SLICE_MASK | GEN8_MCR_SUBSLICE_MASK);
+       I915_WRITE_FW(GEN8_MCR_SELECTOR, mcr);
+
+       intel_uncore_forcewake_put__locked(dev_priv, fw_domains);
+       spin_unlock_irq(&dev_priv->uncore.lock);
+
+       return ret;
+}
+
+/* NB: please notice the memset */
+void intel_engine_get_instdone(struct intel_engine_cs *engine,
+                              struct intel_instdone *instdone)
+{
+       struct drm_i915_private *dev_priv = engine->i915;
+       u32 mmio_base = engine->mmio_base;
+       int slice;
+       int subslice;
+
+       memset(instdone, 0, sizeof(*instdone));
+
+       switch (INTEL_GEN(dev_priv)) {
+       default:
+               instdone->instdone = I915_READ(RING_INSTDONE(mmio_base));
+
+               if (engine->id != RCS)
+                       break;
+
+               instdone->slice_common = I915_READ(GEN7_SC_INSTDONE);
+               for_each_instdone_slice_subslice(dev_priv, slice, subslice) {
+                       instdone->sampler[slice][subslice] =
+                               read_subslice_reg(dev_priv, slice, subslice,
+                                                 GEN7_SAMPLER_INSTDONE);
+                       instdone->row[slice][subslice] =
+                               read_subslice_reg(dev_priv, slice, subslice,
+                                                 GEN7_ROW_INSTDONE);
+               }
+               break;
+       case 7:
+               instdone->instdone = I915_READ(RING_INSTDONE(mmio_base));
+
+               if (engine->id != RCS)
+                       break;
+
+               instdone->slice_common = I915_READ(GEN7_SC_INSTDONE);
+               instdone->sampler[0][0] = I915_READ(GEN7_SAMPLER_INSTDONE);
+               instdone->row[0][0] = I915_READ(GEN7_ROW_INSTDONE);
+
+               break;
+       case 6:
+       case 5:
+       case 4:
+               instdone->instdone = I915_READ(RING_INSTDONE(mmio_base));
+
+               if (engine->id == RCS)
+                       /* HACK: Using the wrong struct member */
+                       instdone->slice_common = I915_READ(GEN4_INSTDONE1);
+               break;
+       case 3:
+       case 2:
+               instdone->instdone = I915_READ(GEN2_INSTDONE);
+               break;
+       }
+}