]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/gpu/drm/i915/i915_gem_context.c
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszer...
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / i915 / i915_gem_context.c
index 5dd84e148bbac2f5e7066990b23033785ff2bced..e5acc3916f75fa4dda6024a4f9c97c504d452349 100644 (file)
@@ -342,15 +342,15 @@ void i915_gem_context_reset(struct drm_device *dev)
                struct intel_context *ctx;
 
                list_for_each_entry(ctx, &dev_priv->context_list, link)
-                       intel_lr_context_reset(dev, ctx);
+                       intel_lr_context_reset(dev_priv, ctx);
        }
 
-       for (i = 0; i < I915_NUM_RINGS; i++) {
-               struct intel_engine_cs *ring = &dev_priv->ring[i];
+       for (i = 0; i < I915_NUM_ENGINES; i++) {
+               struct intel_engine_cs *engine = &dev_priv->engine[i];
 
-               if (ring->last_context) {
-                       i915_gem_context_unpin(ring->last_context, ring);
-                       ring->last_context = NULL;
+               if (engine->last_context) {
+                       i915_gem_context_unpin(engine->last_context, engine);
+                       engine->last_context = NULL;
                }
        }
 
@@ -413,7 +413,7 @@ void i915_gem_context_fini(struct drm_device *dev)
                /* The only known way to stop the gpu from accessing the hw context is
                 * to reset it. Do this as the very last operation to avoid confusing
                 * other code, leading to spurious errors. */
-               intel_gpu_reset(dev);
+               intel_gpu_reset(dev, ALL_ENGINES);
 
                /* When default context is created and switched to, base object refcount
                 * will be 2 (+1 from object creation and +1 from do_switch()).
@@ -421,17 +421,17 @@ void i915_gem_context_fini(struct drm_device *dev)
                 * to default context. So we need to unreference the base object once
                 * to offset the do_switch part, so that i915_gem_context_unreference()
                 * can then free the base object correctly. */
-               WARN_ON(!dev_priv->ring[RCS].last_context);
+               WARN_ON(!dev_priv->engine[RCS].last_context);
 
                i915_gem_object_ggtt_unpin(dctx->legacy_hw_ctx.rcs_state);
        }
 
-       for (i = I915_NUM_RINGS; --i >= 0;) {
-               struct intel_engine_cs *ring = &dev_priv->ring[i];
+       for (i = I915_NUM_ENGINES; --i >= 0;) {
+               struct intel_engine_cs *engine = &dev_priv->engine[i];
 
-               if (ring->last_context) {
-                       i915_gem_context_unpin(ring->last_context, ring);
-                       ring->last_context = NULL;
+               if (engine->last_context) {
+                       i915_gem_context_unpin(engine->last_context, engine);
+                       engine->last_context = NULL;
                }
        }
 
@@ -441,14 +441,14 @@ void i915_gem_context_fini(struct drm_device *dev)
 
 int i915_gem_context_enable(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        int ret;
 
        if (i915.enable_execlists) {
-               if (ring->init_context == NULL)
+               if (engine->init_context == NULL)
                        return 0;
 
-               ret = ring->init_context(req);
+               ret = engine->init_context(req);
        } else
                ret = i915_switch_context(req);
 
@@ -510,133 +510,147 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
 static inline int
 mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
 {
-       struct intel_engine_cs *ring = req->ring;
+       struct intel_engine_cs *engine = req->engine;
        u32 flags = hw_flags | MI_MM_SPACE_GTT;
        const int num_rings =
                /* Use an extended w/a on ivb+ if signalling from other rings */
-               i915_semaphore_is_enabled(ring->dev) ?
-               hweight32(INTEL_INFO(ring->dev)->ring_mask) - 1 :
+               i915_semaphore_is_enabled(engine->dev) ?
+               hweight32(INTEL_INFO(engine->dev)->ring_mask) - 1 :
                0;
-       int len, i, ret;
+       int len, ret;
 
        /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
         * invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value
         * explicitly, so we rely on the value at ring init, stored in
         * itlb_before_ctx_switch.
         */
-       if (IS_GEN6(ring->dev)) {
-               ret = ring->flush(req, I915_GEM_GPU_DOMAINS, 0);
+       if (IS_GEN6(engine->dev)) {
+               ret = engine->flush(req, I915_GEM_GPU_DOMAINS, 0);
                if (ret)
                        return ret;
        }
 
        /* These flags are for resource streamer on HSW+ */
-       if (IS_HASWELL(ring->dev) || INTEL_INFO(ring->dev)->gen >= 8)
+       if (IS_HASWELL(engine->dev) || INTEL_INFO(engine->dev)->gen >= 8)
                flags |= (HSW_MI_RS_SAVE_STATE_EN | HSW_MI_RS_RESTORE_STATE_EN);
-       else if (INTEL_INFO(ring->dev)->gen < 8)
+       else if (INTEL_INFO(engine->dev)->gen < 8)
                flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
 
 
        len = 4;
-       if (INTEL_INFO(ring->dev)->gen >= 7)
-               len += 2 + (num_rings ? 4*num_rings + 2 : 0);
+       if (INTEL_INFO(engine->dev)->gen >= 7)
+               len += 2 + (num_rings ? 4*num_rings + 6 : 0);
 
        ret = intel_ring_begin(req, len);
        if (ret)
                return ret;
 
        /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
-       if (INTEL_INFO(ring->dev)->gen >= 7) {
-               intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
+       if (INTEL_INFO(engine->dev)->gen >= 7) {
+               intel_ring_emit(engine, MI_ARB_ON_OFF | MI_ARB_DISABLE);
                if (num_rings) {
                        struct intel_engine_cs *signaller;
 
-                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
-                       for_each_ring(signaller, to_i915(ring->dev), i) {
-                               if (signaller == ring)
+                       intel_ring_emit(engine,
+                                       MI_LOAD_REGISTER_IMM(num_rings));
+                       for_each_engine(signaller, to_i915(engine->dev)) {
+                               if (signaller == engine)
                                        continue;
 
-                               intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base));
-                               intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+                               intel_ring_emit_reg(engine,
+                                                   RING_PSMI_CTL(signaller->mmio_base));
+                               intel_ring_emit(engine,
+                                               _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
                        }
                }
        }
 
-       intel_ring_emit(ring, MI_NOOP);
-       intel_ring_emit(ring, MI_SET_CONTEXT);
-       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(req->ctx->legacy_hw_ctx.rcs_state) |
+       intel_ring_emit(engine, MI_NOOP);
+       intel_ring_emit(engine, MI_SET_CONTEXT);
+       intel_ring_emit(engine,
+                       i915_gem_obj_ggtt_offset(req->ctx->legacy_hw_ctx.rcs_state) |
                        flags);
        /*
         * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
         * WaMiSetContext_Hang:snb,ivb,vlv
         */
-       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(engine, MI_NOOP);
 
-       if (INTEL_INFO(ring->dev)->gen >= 7) {
+       if (INTEL_INFO(engine->dev)->gen >= 7) {
                if (num_rings) {
                        struct intel_engine_cs *signaller;
+                       i915_reg_t last_reg = {}; /* keep gcc quiet */
 
-                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
-                       for_each_ring(signaller, to_i915(ring->dev), i) {
-                               if (signaller == ring)
+                       intel_ring_emit(engine,
+                                       MI_LOAD_REGISTER_IMM(num_rings));
+                       for_each_engine(signaller, to_i915(engine->dev)) {
+                               if (signaller == engine)
                                        continue;
 
-                               intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base));
-                               intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+                               last_reg = RING_PSMI_CTL(signaller->mmio_base);
+                               intel_ring_emit_reg(engine, last_reg);
+                               intel_ring_emit(engine,
+                                               _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
                        }
+
+                       /* Insert a delay before the next switch! */
+                       intel_ring_emit(engine,
+                                       MI_STORE_REGISTER_MEM |
+                                       MI_SRM_LRM_GLOBAL_GTT);
+                       intel_ring_emit_reg(engine, last_reg);
+                       intel_ring_emit(engine, engine->scratch.gtt_offset);
+                       intel_ring_emit(engine, MI_NOOP);
                }
-               intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
+               intel_ring_emit(engine, MI_ARB_ON_OFF | MI_ARB_ENABLE);
        }
 
-       intel_ring_advance(ring);
+       intel_ring_advance(engine);
 
        return ret;
 }
 
-static inline bool should_skip_switch(struct intel_engine_cs *ring,
-                                     struct intel_context *from,
-                                     struct intel_context *to)
+static inline bool skip_rcs_switch(struct intel_engine_cs *engine,
+                                  struct intel_context *to)
 {
        if (to->remap_slice)
                return false;
 
-       if (to->ppgtt && from == to &&
-           !(intel_ring_flag(ring) & to->ppgtt->pd_dirty_rings))
-               return true;
+       if (!to->legacy_hw_ctx.initialized)
+               return false;
 
-       return false;
+       if (to->ppgtt &&
+           !(intel_engine_flag(engine) & to->ppgtt->pd_dirty_rings))
+               return false;
+
+       return to == engine->last_context;
 }
 
 static bool
-needs_pd_load_pre(struct intel_engine_cs *ring, struct intel_context *to)
+needs_pd_load_pre(struct intel_engine_cs *engine, struct intel_context *to)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-
        if (!to->ppgtt)
                return false;
 
-       if (INTEL_INFO(ring->dev)->gen < 8)
+       if (engine->last_context == to &&
+           !(intel_engine_flag(engine) & to->ppgtt->pd_dirty_rings))
+               return false;
+
+       if (engine->id != RCS)
                return true;
 
-       if (ring != &dev_priv->ring[RCS])
+       if (INTEL_INFO(engine->dev)->gen < 8)
                return true;
 
        return false;
 }
 
 static bool
-needs_pd_load_post(struct intel_engine_cs *ring, struct intel_context *to,
-               u32 hw_flags)
+needs_pd_load_post(struct intel_context *to, u32 hw_flags)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-
        if (!to->ppgtt)
                return false;
 
-       if (!IS_GEN8(ring->dev))
-               return false;
-
-       if (ring != &dev_priv->ring[RCS])
+       if (!IS_GEN8(to->i915))
                return false;
 
        if (hw_flags & MI_RESTORE_INHIBIT)
@@ -645,58 +659,32 @@ needs_pd_load_post(struct intel_engine_cs *ring, struct intel_context *to,
        return false;
 }
 
-static int do_switch(struct drm_i915_gem_request *req)
+static int do_rcs_switch(struct drm_i915_gem_request *req)
 {
        struct intel_context *to = req->ctx;
-       struct intel_engine_cs *ring = req->ring;
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       struct intel_context *from = ring->last_context;
-       u32 hw_flags = 0;
-       bool uninitialized = false;
+       struct intel_engine_cs *engine = req->engine;
+       struct intel_context *from;
+       u32 hw_flags;
        int ret, i;
 
-       if (from != NULL && ring == &dev_priv->ring[RCS]) {
-               BUG_ON(from->legacy_hw_ctx.rcs_state == NULL);
-               BUG_ON(!i915_gem_obj_is_pinned(from->legacy_hw_ctx.rcs_state));
-       }
-
-       if (should_skip_switch(ring, from, to))
+       if (skip_rcs_switch(engine, to))
                return 0;
 
        /* Trying to pin first makes error handling easier. */
-       if (ring == &dev_priv->ring[RCS]) {
-               ret = i915_gem_obj_ggtt_pin(to->legacy_hw_ctx.rcs_state,
-                                           get_context_alignment(ring->dev), 0);
-               if (ret)
-                       return ret;
-       }
+       ret = i915_gem_obj_ggtt_pin(to->legacy_hw_ctx.rcs_state,
+                                   get_context_alignment(engine->dev),
+                                   0);
+       if (ret)
+               return ret;
 
        /*
         * Pin can switch back to the default context if we end up calling into
         * evict_everything - as a last ditch gtt defrag effort that also
         * switches to the default context. Hence we need to reload from here.
+        *
+        * XXX: Doing so is painfully broken!
         */
-       from = ring->last_context;
-
-       if (needs_pd_load_pre(ring, to)) {
-               /* Older GENs and non render rings still want the load first,
-                * "PP_DCLV followed by PP_DIR_BASE register through Load
-                * Register Immediate commands in Ring Buffer before submitting
-                * a context."*/
-               trace_switch_mm(ring, to);
-               ret = to->ppgtt->switch_mm(to->ppgtt, req);
-               if (ret)
-                       goto unpin_out;
-
-               /* Doing a PD load always reloads the page dirs */
-               to->ppgtt->pd_dirty_rings &= ~intel_ring_flag(ring);
-       }
-
-       if (ring != &dev_priv->ring[RCS]) {
-               if (from)
-                       i915_gem_context_unreference(from);
-               goto done;
-       }
+       from = engine->last_context;
 
        /*
         * Clear this page out of any CPU caches for coherent swap-in/out. Note
@@ -710,53 +698,37 @@ static int do_switch(struct drm_i915_gem_request *req)
        if (ret)
                goto unpin_out;
 
-       if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) {
-               hw_flags |= MI_RESTORE_INHIBIT;
+       if (needs_pd_load_pre(engine, to)) {
+               /* Older GENs and non render rings still want the load first,
+                * "PP_DCLV followed by PP_DIR_BASE register through Load
+                * Register Immediate commands in Ring Buffer before submitting
+                * a context."*/
+               trace_switch_mm(engine, to);
+               ret = to->ppgtt->switch_mm(to->ppgtt, req);
+               if (ret)
+                       goto unpin_out;
+       }
+
+       if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
                /* NB: If we inhibit the restore, the context is not allowed to
                 * die because future work may end up depending on valid address
                 * space. This means we must enforce that a page table load
                 * occur when this occurs. */
-       } else if (to->ppgtt &&
-                  (intel_ring_flag(ring) & to->ppgtt->pd_dirty_rings)) {
-               hw_flags |= MI_FORCE_RESTORE;
-               to->ppgtt->pd_dirty_rings &= ~intel_ring_flag(ring);
-       }
+               hw_flags = MI_RESTORE_INHIBIT;
+       else if (to->ppgtt &&
+                intel_engine_flag(engine) & to->ppgtt->pd_dirty_rings)
+               hw_flags = MI_FORCE_RESTORE;
+       else
+               hw_flags = 0;
 
        /* We should never emit switch_mm more than once */
-       WARN_ON(needs_pd_load_pre(ring, to) &&
-               needs_pd_load_post(ring, to, hw_flags));
-
-       ret = mi_set_context(req, hw_flags);
-       if (ret)
-               goto unpin_out;
+       WARN_ON(needs_pd_load_pre(engine, to) &&
+               needs_pd_load_post(to, hw_flags));
 
-       /* GEN8 does *not* require an explicit reload if the PDPs have been
-        * setup, and we do not wish to move them.
-        */
-       if (needs_pd_load_post(ring, to, hw_flags)) {
-               trace_switch_mm(ring, to);
-               ret = to->ppgtt->switch_mm(to->ppgtt, req);
-               /* The hardware context switch is emitted, but we haven't
-                * actually changed the state - so it's probably safe to bail
-                * here. Still, let the user know something dangerous has
-                * happened.
-                */
-               if (ret) {
-                       DRM_ERROR("Failed to change address space on context switch\n");
-                       goto unpin_out;
-               }
-       }
-
-       for (i = 0; i < MAX_L3_SLICES; i++) {
-               if (!(to->remap_slice & (1<<i)))
-                       continue;
-
-               ret = i915_gem_l3_remap(req, i);
-               /* If it failed, try again next round */
+       if (to != from || (hw_flags & MI_FORCE_RESTORE)) {
+               ret = mi_set_context(req, hw_flags);
                if (ret)
-                       DRM_DEBUG_DRIVER("L3 remapping failed\n");
-               else
-                       to->remap_slice &= ~(1<<i);
+                       goto unpin_out;
        }
 
        /* The backing object for the context is done after switching to the
@@ -781,27 +753,51 @@ static int do_switch(struct drm_i915_gem_request *req)
                i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state);
                i915_gem_context_unreference(from);
        }
+       i915_gem_context_reference(to);
+       engine->last_context = to;
+
+       /* GEN8 does *not* require an explicit reload if the PDPs have been
+        * setup, and we do not wish to move them.
+        */
+       if (needs_pd_load_post(to, hw_flags)) {
+               trace_switch_mm(engine, to);
+               ret = to->ppgtt->switch_mm(to->ppgtt, req);
+               /* The hardware context switch is emitted, but we haven't
+                * actually changed the state - so it's probably safe to bail
+                * here. Still, let the user know something dangerous has
+                * happened.
+                */
+               if (ret)
+                       return ret;
+       }
 
-       uninitialized = !to->legacy_hw_ctx.initialized;
-       to->legacy_hw_ctx.initialized = true;
+       if (to->ppgtt)
+               to->ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
 
-done:
-       i915_gem_context_reference(to);
-       ring->last_context = to;
+       for (i = 0; i < MAX_L3_SLICES; i++) {
+               if (!(to->remap_slice & (1<<i)))
+                       continue;
+
+               ret = i915_gem_l3_remap(req, i);
+               if (ret)
+                       return ret;
 
-       if (uninitialized) {
-               if (ring->init_context) {
-                       ret = ring->init_context(req);
+               to->remap_slice &= ~(1<<i);
+       }
+
+       if (!to->legacy_hw_ctx.initialized) {
+               if (engine->init_context) {
+                       ret = engine->init_context(req);
                        if (ret)
-                               DRM_ERROR("ring init context: %d\n", ret);
+                               return ret;
                }
+               to->legacy_hw_ctx.initialized = true;
        }
 
        return 0;
 
 unpin_out:
-       if (ring->id == RCS)
-               i915_gem_object_ggtt_unpin(to->legacy_hw_ctx.rcs_state);
+       i915_gem_object_ggtt_unpin(to->legacy_hw_ctx.rcs_state);
        return ret;
 }
 
@@ -820,23 +816,39 @@ unpin_out:
  */
 int i915_switch_context(struct drm_i915_gem_request *req)
 {
-       struct intel_engine_cs *ring = req->ring;
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct intel_engine_cs *engine = req->engine;
+       struct drm_i915_private *dev_priv = req->i915;
 
        WARN_ON(i915.enable_execlists);
        WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
-       if (req->ctx->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
-               if (req->ctx != ring->last_context) {
-                       i915_gem_context_reference(req->ctx);
-                       if (ring->last_context)
-                               i915_gem_context_unreference(ring->last_context);
-                       ring->last_context = req->ctx;
+       if (engine->id != RCS ||
+           req->ctx->legacy_hw_ctx.rcs_state == NULL) {
+               struct intel_context *to = req->ctx;
+
+               if (needs_pd_load_pre(engine, to)) {
+                       int ret;
+
+                       trace_switch_mm(engine, to);
+                       ret = to->ppgtt->switch_mm(to->ppgtt, req);
+                       if (ret)
+                               return ret;
+
+                       /* Doing a PD load always reloads the page dirs */
+                       to->ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
                }
+
+               if (to != engine->last_context) {
+                       i915_gem_context_reference(to);
+                       if (engine->last_context)
+                               i915_gem_context_unreference(engine->last_context);
+                       engine->last_context = to;
+               }
+
                return 0;
        }
 
-       return do_switch(req);
+       return do_rcs_switch(req);
 }
 
 static bool contexts_enabled(struct drm_device *dev)
@@ -937,7 +949,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
                else if (to_i915(dev)->mm.aliasing_ppgtt)
                        args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total;
                else
-                       args->value = to_i915(dev)->gtt.base.total;
+                       args->value = to_i915(dev)->ggtt.base.total;
                break;
        default:
                ret = -EINVAL;