drm/i915/skl: Program the DDB allocation
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_gem_context.c
index 3b99390e467aa3bfabcfb99438d66981ec2509c0..7d3257111737e7babdb37d48f4269172c62cec3d 100644 (file)
 #define GEN6_CONTEXT_ALIGN (64<<10)
 #define GEN7_CONTEXT_ALIGN 4096
 
-static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
-{
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_address_space *vm = &ppgtt->base;
-
-       if (ppgtt == dev_priv->mm.aliasing_ppgtt ||
-           (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) {
-               ppgtt->base.cleanup(&ppgtt->base);
-               return;
-       }
-
-       /*
-        * Make sure vmas are unbound before we take down the drm_mm
-        *
-        * FIXME: Proper refcounting should take care of this, this shouldn't be
-        * needed at all.
-        */
-       if (!list_empty(&vm->active_list)) {
-               struct i915_vma *vma;
-
-               list_for_each_entry(vma, &vm->active_list, mm_list)
-                       if (WARN_ON(list_empty(&vma->vma_link) ||
-                                   list_is_singular(&vma->vma_link)))
-                               break;
-
-               i915_gem_evict_vm(&ppgtt->base, true);
-       } else {
-               i915_gem_retire_requests(dev);
-               i915_gem_evict_vm(&ppgtt->base, false);
-       }
-
-       ppgtt->base.cleanup(&ppgtt->base);
-}
-
-static void ppgtt_release(struct kref *kref)
-{
-       struct i915_hw_ppgtt *ppgtt =
-               container_of(kref, struct i915_hw_ppgtt, ref);
-
-       do_ppgtt_cleanup(ppgtt);
-       kfree(ppgtt);
-}
-
 static size_t get_context_alignment(struct drm_device *dev)
 {
        if (IS_GEN6(dev))
@@ -179,24 +135,20 @@ static int get_context_size(struct drm_device *dev)
 void i915_gem_context_free(struct kref *ctx_ref)
 {
        struct intel_context *ctx = container_of(ctx_ref,
-                                                  typeof(*ctx), ref);
-       struct i915_hw_ppgtt *ppgtt = NULL;
+                                                typeof(*ctx), ref);
 
-       if (ctx->legacy_hw_ctx.rcs_state) {
-               /* We refcount even the aliasing PPGTT to keep the code symmetric */
-               if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev))
-                       ppgtt = ctx_to_ppgtt(ctx);
-       }
+       if (i915.enable_execlists)
+               intel_lr_context_free(ctx);
+
+       i915_ppgtt_put(ctx->ppgtt);
 
-       if (ppgtt)
-               kref_put(&ppgtt->ref, ppgtt_release);
        if (ctx->legacy_hw_ctx.rcs_state)
                drm_gem_object_unreference(&ctx->legacy_hw_ctx.rcs_state->base);
        list_del(&ctx->link);
        kfree(ctx);
 }
 
-static struct drm_i915_gem_object *
+struct drm_i915_gem_object *
 i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
 {
        struct drm_i915_gem_object *obj;
@@ -226,29 +178,9 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
        return obj;
 }
 
-static struct i915_hw_ppgtt *
-create_vm_for_ctx(struct drm_device *dev, struct intel_context *ctx)
-{
-       struct i915_hw_ppgtt *ppgtt;
-       int ret;
-
-       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
-       if (!ppgtt)
-               return ERR_PTR(-ENOMEM);
-
-       ret = i915_gem_init_ppgtt(dev, ppgtt);
-       if (ret) {
-               kfree(ppgtt);
-               return ERR_PTR(ret);
-       }
-
-       ppgtt->ctx = ctx;
-       return ppgtt;
-}
-
 static struct intel_context *
 __create_hw_context(struct drm_device *dev,
-                 struct drm_i915_file_private *file_priv)
+                   struct drm_i915_file_private *file_priv)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_context *ctx;
@@ -301,11 +233,9 @@ err_out:
  */
 static struct intel_context *
 i915_gem_create_context(struct drm_device *dev,
-                       struct drm_i915_file_private *file_priv,
-                       bool create_vm)
+                       struct drm_i915_file_private *file_priv)
 {
        const bool is_global_default_ctx = file_priv == NULL;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_context *ctx;
        int ret = 0;
 
@@ -331,34 +261,18 @@ i915_gem_create_context(struct drm_device *dev,
                }
        }
 
-       if (create_vm) {
-               struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx);
+       if (USES_FULL_PPGTT(dev)) {
+               struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv);
 
                if (IS_ERR_OR_NULL(ppgtt)) {
                        DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
                                         PTR_ERR(ppgtt));
                        ret = PTR_ERR(ppgtt);
                        goto err_unpin;
-               } else
-                       ctx->vm = &ppgtt->base;
-
-               /* This case is reserved for the global default context and
-                * should only happen once. */
-               if (is_global_default_ctx) {
-                       if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) {
-                               ret = -EEXIST;
-                               goto err_unpin;
-                       }
-
-                       dev_priv->mm.aliasing_ppgtt = ppgtt;
                }
-       } else if (USES_PPGTT(dev)) {
-               /* For platforms which only have aliasing PPGTT, we fake the
-                * address space and refcounting. */
-               ctx->vm = &dev_priv->mm.aliasing_ppgtt->base;
-               kref_get(&dev_priv->mm.aliasing_ppgtt->ref);
-       } else
-               ctx->vm = &dev_priv->gtt.base;
+
+               ctx->ppgtt = ppgtt;
+       }
 
        return ctx;
 
@@ -375,34 +289,23 @@ void i915_gem_context_reset(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       /* Prevent the hardware from restoring the last context (which hung) on
-        * the next switch */
+       /* In execlists mode we will unreference the context when the execlist
+        * queue is cleared and the requests destroyed.
+        */
+       if (i915.enable_execlists)
+               return;
+
        for (i = 0; i < I915_NUM_RINGS; i++) {
                struct intel_engine_cs *ring = &dev_priv->ring[i];
-               struct intel_context *dctx = ring->default_context;
                struct intel_context *lctx = ring->last_context;
 
-               /* Do a fake switch to the default context */
-               if (lctx == dctx)
-                       continue;
-
-               if (!lctx)
-                       continue;
+               if (lctx) {
+                       if (lctx->legacy_hw_ctx.rcs_state && i == RCS)
+                               i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state);
 
-               if (dctx->legacy_hw_ctx.rcs_state && i == RCS) {
-                       WARN_ON(i915_gem_obj_ggtt_pin(dctx->legacy_hw_ctx.rcs_state,
-                                                     get_context_alignment(dev), 0));
-                       /* Fake a finish/inactive */
-                       dctx->legacy_hw_ctx.rcs_state->base.write_domain = 0;
-                       dctx->legacy_hw_ctx.rcs_state->active = 0;
+                       i915_gem_context_unreference(lctx);
+                       ring->last_context = NULL;
                }
-
-               if (lctx->legacy_hw_ctx.rcs_state && i == RCS)
-                       i915_gem_object_ggtt_unpin(lctx->legacy_hw_ctx.rcs_state);
-
-               i915_gem_context_unreference(lctx);
-               i915_gem_context_reference(dctx);
-               ring->last_context = dctx;
        }
 }
 
@@ -417,7 +320,11 @@ int i915_gem_context_init(struct drm_device *dev)
        if (WARN_ON(dev_priv->ring[RCS].default_context))
                return 0;
 
-       if (HAS_HW_CONTEXTS(dev)) {
+       if (i915.enable_execlists) {
+               /* NB: intentionally left blank. We will allocate our own
+                * backing objects as we need them, thank you very much */
+               dev_priv->hw_context_size = 0;
+       } else if (HAS_HW_CONTEXTS(dev)) {
                dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
                if (dev_priv->hw_context_size > (1<<20)) {
                        DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
@@ -426,18 +333,23 @@ int i915_gem_context_init(struct drm_device *dev)
                }
        }
 
-       ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, NULL);
        if (IS_ERR(ctx)) {
                DRM_ERROR("Failed to create default global context (error %ld)\n",
                          PTR_ERR(ctx));
                return PTR_ERR(ctx);
        }
 
-       /* NB: RCS will hold a ref for all rings */
-       for (i = 0; i < I915_NUM_RINGS; i++)
-               dev_priv->ring[i].default_context = ctx;
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct intel_engine_cs *ring = &dev_priv->ring[i];
+
+               /* NB: RCS will hold a ref for all rings */
+               ring->default_context = ctx;
+       }
 
-       DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");
+       DRM_DEBUG_DRIVER("%s context support initialized\n",
+                       i915.enable_execlists ? "LR" :
+                       dev_priv->hw_context_size ? "HW" : "fake");
        return 0;
 }
 
@@ -489,19 +401,11 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
        struct intel_engine_cs *ring;
        int ret, i;
 
-       /* This is the only place the aliasing PPGTT gets enabled, which means
-        * it has to happen before we bail on reset */
-       if (dev_priv->mm.aliasing_ppgtt) {
-               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-               ppgtt->enable(ppgtt);
-       }
+       BUG_ON(!dev_priv->ring[RCS].default_context);
 
-       /* FIXME: We should make this work, even in reset */
-       if (i915_reset_in_progress(&dev_priv->gpu_error))
+       if (i915.enable_execlists)
                return 0;
 
-       BUG_ON(!dev_priv->ring[RCS].default_context);
-
        for_each_ring(ring, dev_priv, i) {
                ret = i915_switch_context(ring, ring->default_context);
                if (ret)
@@ -527,7 +431,7 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
        idr_init(&file_priv->context_idr);
 
        mutex_lock(&dev->struct_mutex);
-       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, file_priv);
        mutex_unlock(&dev->struct_mutex);
 
        if (IS_ERR(ctx)) {
@@ -563,6 +467,7 @@ mi_set_context(struct intel_engine_cs *ring,
               struct intel_context *new_context,
               u32 hw_flags)
 {
+       u32 flags = hw_flags | MI_MM_SPACE_GTT;
        int ret;
 
        /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
@@ -576,6 +481,10 @@ mi_set_context(struct intel_engine_cs *ring,
                        return ret;
        }
 
+       /* These flags are for resource streamer on HSW+ */
+       if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8)
+               flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
+
        ret = intel_ring_begin(ring, 6);
        if (ret)
                return ret;
@@ -589,10 +498,7 @@ mi_set_context(struct intel_engine_cs *ring,
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_emit(ring, MI_SET_CONTEXT);
        intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->legacy_hw_ctx.rcs_state) |
-                       MI_MM_SPACE_GTT |
-                       MI_SAVE_EXT_STATE_EN |
-                       MI_RESTORE_EXT_STATE_EN |
-                       hw_flags);
+                       flags);
        /*
         * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
         * WaMiSetContext_Hang:snb,ivb,vlv
@@ -614,9 +520,9 @@ static int do_switch(struct intel_engine_cs *ring,
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct intel_context *from = ring->last_context;
-       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to);
        u32 hw_flags = 0;
        bool uninitialized = false;
+       struct i915_vma *vma;
        int ret, i;
 
        if (from != NULL && ring == &dev_priv->ring[RCS]) {
@@ -642,8 +548,8 @@ static int do_switch(struct intel_engine_cs *ring,
         */
        from = ring->last_context;
 
-       if (USES_FULL_PPGTT(ring->dev)) {
-               ret = ppgtt->switch_mm(ppgtt, ring, false);
+       if (to->ppgtt) {
+               ret = to->ppgtt->switch_mm(to->ppgtt, ring);
                if (ret)
                        goto unpin_out;
        }
@@ -666,11 +572,10 @@ static int do_switch(struct intel_engine_cs *ring,
        if (ret)
                goto unpin_out;
 
-       if (!to->legacy_hw_ctx.rcs_state->has_global_gtt_mapping) {
-               struct i915_vma *vma = i915_gem_obj_to_vma(to->legacy_hw_ctx.rcs_state,
-                                                          &dev_priv->gtt.base);
-               vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level, GLOBAL_BIND);
-       }
+       vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state);
+       if (!(vma->bound & GLOBAL_BIND))
+               vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level,
+                               GLOBAL_BIND);
 
        if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
                hw_flags |= MI_RESTORE_INHIBIT;
@@ -723,6 +628,12 @@ done:
        ring->last_context = to;
 
        if (uninitialized) {
+               if (ring->init_context) {
+                       ret = ring->init_context(ring);
+                       if (ret)
+                               DRM_ERROR("ring init context: %d\n", ret);
+               }
+
                ret = i915_gem_render_state_init(ring);
                if (ret)
                        DRM_ERROR("init render state: %d\n", ret);
@@ -743,14 +654,19 @@ unpin_out:
  *
  * The context life cycle is simple. The context refcount is incremented and
  * decremented by 1 and create and destroy. If the context is in use by the GPU,
- * it will have a refoucnt > 1. This allows us to destroy the context abstract
+ * it will have a refcount > 1. This allows us to destroy the context abstract
  * object while letting the normal object tracking destroy the backing BO.
+ *
+ * This function should not be used in execlists mode.  Instead the context is
+ * switched by writing to the ELSP and requests keep a reference to their
+ * context.
  */
 int i915_switch_context(struct intel_engine_cs *ring,
                        struct intel_context *to)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
+       WARN_ON(i915.enable_execlists);
        WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
        if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
@@ -766,9 +682,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
        return do_switch(ring, to);
 }
 
-static bool hw_context_enabled(struct drm_device *dev)
+static bool contexts_enabled(struct drm_device *dev)
 {
-       return to_i915(dev)->hw_context_size;
+       return i915.enable_execlists || to_i915(dev)->hw_context_size;
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -779,14 +695,14 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        struct intel_context *ctx;
        int ret;
 
-       if (!hw_context_enabled(dev))
+       if (!contexts_enabled(dev))
                return -ENODEV;
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
 
-       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, file_priv);
        mutex_unlock(&dev->struct_mutex);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
This page took 0.030055 seconds and 5 git commands to generate.