Merge tag 'drm-intel-next-2018-07-19' of git://anongit.freedesktop.org/drm/drm-intel...
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / i915 / intel_ringbuffer.c
index 8f19349..33faad3 100644 (file)
@@ -496,6 +496,10 @@ static int init_ring_common(struct intel_engine_cs *engine)
                DRM_DEBUG_DRIVER("%s initialization failed [head=%08x], fudging\n",
                                 engine->name, I915_READ_HEAD(engine));
 
+       /* Check that the ring offsets point within the ring! */
+       GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->head));
+       GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->tail));
+
        intel_ring_update_space(ring);
        I915_WRITE_HEAD(engine, ring->head);
        I915_WRITE_TAIL(engine, ring->tail);
@@ -520,8 +524,6 @@ static int init_ring_common(struct intel_engine_cs *engine)
                goto out;
        }
 
-       intel_engine_init_hangcheck(engine);
-
        if (INTEL_GEN(dev_priv) > 2)
                I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING));
 
@@ -531,16 +533,33 @@ out:
        return ret;
 }
 
-static void reset_ring_common(struct intel_engine_cs *engine,
-                             struct i915_request *request)
+static struct i915_request *reset_prepare(struct intel_engine_cs *engine)
 {
-       /*
-        * RC6 must be prevented until the reset is complete and the engine
-        * reinitialised. If it occurs in the middle of this sequence, the
-        * state written to/loaded from the power context is ill-defined (e.g.
-        * the PP_BASE_DIR may be lost).
-        */
-       assert_forcewakes_active(engine->i915, FORCEWAKE_ALL);
+       intel_engine_stop_cs(engine);
+
+       if (engine->irq_seqno_barrier)
+               engine->irq_seqno_barrier(engine);
+
+       return i915_gem_find_active_request(engine);
+}
+
+static void skip_request(struct i915_request *rq)
+{
+       void *vaddr = rq->ring->vaddr;
+       u32 head;
+
+       head = rq->infix;
+       if (rq->postfix < head) {
+               memset32(vaddr + head, MI_NOOP,
+                        (rq->ring->size - head) / sizeof(u32));
+               head = 0;
+       }
+       memset32(vaddr + head, MI_NOOP, (rq->postfix - head) / sizeof(u32));
+}
+
+static void reset_ring(struct intel_engine_cs *engine, struct i915_request *rq)
+{
+       GEM_TRACE("%s seqno=%x\n", engine->name, rq ? rq->global_seqno : 0);
 
        /*
         * Try to restore the logical GPU state to match the continuation
@@ -556,47 +575,18 @@ static void reset_ring_common(struct intel_engine_cs *engine,
         * If the request was innocent, we try to replay the request with
         * the restored context.
         */
-       if (request) {
-               struct drm_i915_private *dev_priv = request->i915;
-               struct intel_context *ce = to_intel_context(request->ctx,
-                                                           engine);
-               struct i915_hw_ppgtt *ppgtt;
-
-               if (ce->state) {
-                       I915_WRITE(CCID,
-                                  i915_ggtt_offset(ce->state) |
-                                  BIT(8) /* must be set! */ |
-                                  CCID_EXTENDED_STATE_SAVE |
-                                  CCID_EXTENDED_STATE_RESTORE |
-                                  CCID_EN);
-               }
-
-               ppgtt = request->ctx->ppgtt ?: engine->i915->mm.aliasing_ppgtt;
-               if (ppgtt) {
-                       u32 pd_offset = ppgtt->pd.base.ggtt_offset << 10;
-
-                       I915_WRITE(RING_PP_DIR_DCLV(engine), PP_DIR_DCLV_2G);
-                       I915_WRITE(RING_PP_DIR_BASE(engine), pd_offset);
-
-                       /* Wait for the PD reload to complete */
-                       if (intel_wait_for_register(dev_priv,
-                                                   RING_PP_DIR_BASE(engine),
-                                                   BIT(0), 0,
-                                                   10))
-                               DRM_ERROR("Wait for reload of ppgtt page-directory timed out\n");
-
-                       ppgtt->pd_dirty_rings &= ~intel_engine_flag(engine);
-               }
-
+       if (rq) {
                /* If the rq hung, jump to its breadcrumb and skip the batch */
-               if (request->fence.error == -EIO)
-                       request->ring->head = request->postfix;
-       } else {
-               engine->legacy_active_context = NULL;
-               engine->legacy_active_ppgtt = NULL;
+               rq->ring->head = intel_ring_wrap(rq->ring, rq->head);
+               if (rq->fence.error == -EIO)
+                       skip_request(rq);
        }
 }
 
+static void reset_finish(struct intel_engine_cs *engine)
+{
+}
+
 static int intel_rcs_ctx_init(struct i915_request *rq)
 {
        int ret;
@@ -1033,6 +1023,8 @@ int intel_ring_pin(struct intel_ring *ring,
                flags |= PIN_OFFSET_BIAS | offset_bias;
        if (vma->obj->stolen)
                flags |= PIN_MAPPABLE;
+       else
+               flags |= PIN_HIGH;
 
        if (!(vma->flags & I915_VMA_GLOBAL_BIND)) {
                if (flags & PIN_MAPPABLE || map == I915_MAP_WC)
@@ -1066,6 +1058,8 @@ err:
 
 void intel_ring_reset(struct intel_ring *ring, u32 tail)
 {
+       GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
+
        ring->tail = tail;
        ring->head = tail;
        ring->emit = tail;
@@ -1093,6 +1087,7 @@ void intel_ring_unpin(struct intel_ring *ring)
 static struct i915_vma *
 intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
 {
+       struct i915_address_space *vm = &dev_priv->ggtt.vm;
        struct drm_i915_gem_object *obj;
        struct i915_vma *vma;
 
@@ -1102,10 +1097,14 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
        if (IS_ERR(obj))
                return ERR_CAST(obj);
 
-       /* mark ring buffers as read-only from GPU side by default */
-       obj->gt_ro = 1;
+       /*
+        * Mark ring buffers as read-only from GPU side (so no stray overwrites)
+        * if supported by the platform's GGTT.
+        */
+       if (vm->has_read_only)
+               i915_gem_object_set_readonly(obj);
 
-       vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL);
+       vma = i915_vma_instance(obj, vm, NULL);
        if (IS_ERR(vma))
                goto err;
 
@@ -1169,10 +1168,46 @@ intel_ring_free(struct intel_ring *ring)
        kfree(ring);
 }
 
-static int context_pin(struct intel_context *ce)
+static void intel_ring_context_destroy(struct intel_context *ce)
 {
-       struct i915_vma *vma = ce->state;
-       int ret;
+       GEM_BUG_ON(ce->pin_count);
+
+       if (!ce->state)
+               return;
+
+       GEM_BUG_ON(i915_gem_object_is_active(ce->state->obj));
+       i915_gem_object_put(ce->state->obj);
+}
+
+static int __context_pin_ppgtt(struct i915_gem_context *ctx)
+{
+       struct i915_hw_ppgtt *ppgtt;
+       int err = 0;
+
+       ppgtt = ctx->ppgtt ?: ctx->i915->mm.aliasing_ppgtt;
+       if (ppgtt)
+               err = gen6_ppgtt_pin(ppgtt);
+
+       return err;
+}
+
+static void __context_unpin_ppgtt(struct i915_gem_context *ctx)
+{
+       struct i915_hw_ppgtt *ppgtt;
+
+       ppgtt = ctx->ppgtt ?: ctx->i915->mm.aliasing_ppgtt;
+       if (ppgtt)
+               gen6_ppgtt_unpin(ppgtt);
+}
+
+static int __context_pin(struct intel_context *ce)
+{
+       struct i915_vma *vma;
+       int err;
+
+       vma = ce->state;
+       if (!vma)
+               return 0;
 
        /*
         * Clear this page out of any CPU caches for coherent swap-in/out.
@@ -1180,13 +1215,43 @@ static int context_pin(struct intel_context *ce)
         * on an active context (which by nature is already on the GPU).
         */
        if (!(vma->flags & I915_VMA_GLOBAL_BIND)) {
-               ret = i915_gem_object_set_to_gtt_domain(vma->obj, true);
-               if (ret)
-                       return ret;
+               err = i915_gem_object_set_to_gtt_domain(vma->obj, true);
+               if (err)
+                       return err;
        }
 
-       return i915_vma_pin(vma, 0, I915_GTT_MIN_ALIGNMENT,
-                           PIN_GLOBAL | PIN_HIGH);
+       err = i915_vma_pin(vma, 0, I915_GTT_MIN_ALIGNMENT,
+                          PIN_GLOBAL | PIN_HIGH);
+       if (err)
+               return err;
+
+       /*
+        * And mark is as a globally pinned object to let the shrinker know
+        * it cannot reclaim the object until we release it.
+        */
+       vma->obj->pin_global++;
+
+       return 0;
+}
+
+static void __context_unpin(struct intel_context *ce)
+{
+       struct i915_vma *vma;
+
+       vma = ce->state;
+       if (!vma)
+               return;
+
+       vma->obj->pin_global--;
+       i915_vma_unpin(vma);
+}
+
+static void intel_ring_context_unpin(struct intel_context *ce)
+{
+       __context_unpin_ppgtt(ce->gem_context);
+       __context_unpin(ce);
+
+       i915_gem_context_put(ce->gem_context);
 }
 
 static struct i915_vma *
@@ -1243,7 +1308,7 @@ alloc_context_vma(struct intel_engine_cs *engine)
                i915_gem_object_set_cache_level(obj, I915_CACHE_L3_LLC);
        }
 
-       vma = i915_vma_instance(obj, &i915->ggtt.base, NULL);
+       vma = i915_vma_instance(obj, &i915->ggtt.vm, NULL);
        if (IS_ERR(vma)) {
                err = PTR_ERR(vma);
                goto err_obj;
@@ -1258,81 +1323,79 @@ err_obj:
        return ERR_PTR(err);
 }
 
-static struct intel_ring *
-intel_ring_context_pin(struct intel_engine_cs *engine,
-                      struct i915_gem_context *ctx)
+static struct intel_context *
+__ring_context_pin(struct intel_engine_cs *engine,
+                  struct i915_gem_context *ctx,
+                  struct intel_context *ce)
 {
-       struct intel_context *ce = to_intel_context(ctx, engine);
-       int ret;
-
-       lockdep_assert_held(&ctx->i915->drm.struct_mutex);
-
-       if (likely(ce->pin_count++))
-               goto out;
-       GEM_BUG_ON(!ce->pin_count); /* no overflow please! */
+       int err;
 
        if (!ce->state && engine->context_size) {
                struct i915_vma *vma;
 
                vma = alloc_context_vma(engine);
                if (IS_ERR(vma)) {
-                       ret = PTR_ERR(vma);
+                       err = PTR_ERR(vma);
                        goto err;
                }
 
                ce->state = vma;
        }
 
-       if (ce->state) {
-               ret = context_pin(ce);
-               if (ret)
-                       goto err;
+       err = __context_pin(ce);
+       if (err)
+               goto err;
 
-               ce->state->obj->pin_global++;
-       }
+       err = __context_pin_ppgtt(ce->gem_context);
+       if (err)
+               goto err_unpin;
 
        i915_gem_context_get(ctx);
 
-out:
        /* One ringbuffer to rule them all */
-       return engine->buffer;
+       GEM_BUG_ON(!engine->buffer);
+       ce->ring = engine->buffer;
+
+       return ce;
 
+err_unpin:
+       __context_unpin(ce);
 err:
        ce->pin_count = 0;
-       return ERR_PTR(ret);
+       return ERR_PTR(err);
 }
 
-static void intel_ring_context_unpin(struct intel_engine_cs *engine,
-                                    struct i915_gem_context *ctx)
+static const struct intel_context_ops ring_context_ops = {
+       .unpin = intel_ring_context_unpin,
+       .destroy = intel_ring_context_destroy,
+};
+
+static struct intel_context *
+intel_ring_context_pin(struct intel_engine_cs *engine,
+                      struct i915_gem_context *ctx)
 {
        struct intel_context *ce = to_intel_context(ctx, engine);
 
        lockdep_assert_held(&ctx->i915->drm.struct_mutex);
-       GEM_BUG_ON(ce->pin_count == 0);
 
-       if (--ce->pin_count)
-               return;
+       if (likely(ce->pin_count++))
+               return ce;
+       GEM_BUG_ON(!ce->pin_count); /* no overflow please! */
 
-       if (ce->state) {
-               ce->state->obj->pin_global--;
-               i915_vma_unpin(ce->state);
-       }
+       ce->ops = &ring_context_ops;
 
-       i915_gem_context_put(ctx);
+       return __ring_context_pin(engine, ctx, ce);
 }
 
 static int intel_init_ring_buffer(struct intel_engine_cs *engine)
 {
-       struct intel_ring *ring;
        struct i915_timeline *timeline;
+       struct intel_ring *ring;
+       unsigned int size;
        int err;
 
        intel_engine_setup_common(engine);
 
-       err = intel_engine_init_common(engine);
-       if (err)
-               goto err;
-
        timeline = i915_timeline_create(engine->i915, engine->name);
        if (IS_ERR(timeline)) {
                err = PTR_ERR(timeline);
@@ -1354,8 +1417,23 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
        GEM_BUG_ON(engine->buffer);
        engine->buffer = ring;
 
+       size = PAGE_SIZE;
+       if (HAS_BROKEN_CS_TLB(engine->i915))
+               size = I830_WA_SIZE;
+       err = intel_engine_create_scratch(engine, size);
+       if (err)
+               goto err_unpin;
+
+       err = intel_engine_init_common(engine);
+       if (err)
+               goto err_scratch;
+
        return 0;
 
+err_scratch:
+       intel_engine_cleanup_scratch(engine);
+err_unpin:
+       intel_ring_unpin(ring);
 err_ring:
        intel_ring_free(ring);
 err:
@@ -1392,6 +1470,48 @@ void intel_legacy_submission_resume(struct drm_i915_private *dev_priv)
                intel_ring_reset(engine->buffer, 0);
 }
 
+static int load_pd_dir(struct i915_request *rq,
+                      const struct i915_hw_ppgtt *ppgtt)
+{
+       const struct intel_engine_cs * const engine = rq->engine;
+       u32 *cs;
+
+       cs = intel_ring_begin(rq, 6);
+       if (IS_ERR(cs))
+               return PTR_ERR(cs);
+
+       *cs++ = MI_LOAD_REGISTER_IMM(1);
+       *cs++ = i915_mmio_reg_offset(RING_PP_DIR_DCLV(engine));
+       *cs++ = PP_DIR_DCLV_2G;
+
+       *cs++ = MI_LOAD_REGISTER_IMM(1);
+       *cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine));
+       *cs++ = ppgtt->pd.base.ggtt_offset << 10;
+
+       intel_ring_advance(rq, cs);
+
+       return 0;
+}
+
+static int flush_pd_dir(struct i915_request *rq)
+{
+       const struct intel_engine_cs * const engine = rq->engine;
+       u32 *cs;
+
+       cs = intel_ring_begin(rq, 4);
+       if (IS_ERR(cs))
+               return PTR_ERR(cs);
+
+       /* Stall until the page table load is complete */
+       *cs++ = MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT;
+       *cs++ = i915_mmio_reg_offset(RING_PP_DIR_BASE(engine));
+       *cs++ = i915_ggtt_offset(engine->scratch);
+       *cs++ = MI_NOOP;
+
+       intel_ring_advance(rq, cs);
+       return 0;
+}
+
 static inline int mi_set_context(struct i915_request *rq, u32 flags)
 {
        struct drm_i915_private *i915 = rq->i915;
@@ -1402,6 +1522,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags)
                (HAS_LEGACY_SEMAPHORES(i915) && IS_GEN7(i915)) ?
                INTEL_INFO(i915)->num_rings - 1 :
                0;
+       bool force_restore = false;
        int len;
        u32 *cs;
 
@@ -1415,6 +1536,12 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags)
        len = 4;
        if (IS_GEN7(i915))
                len += 2 + (num_rings ? 4*num_rings + 6 : 0);
+       if (flags & MI_FORCE_RESTORE) {
+               GEM_BUG_ON(flags & MI_RESTORE_INHIBIT);
+               flags &= ~MI_FORCE_RESTORE;
+               force_restore = true;
+               len += 2;
+       }
 
        cs = intel_ring_begin(rq, len);
        if (IS_ERR(cs))
@@ -1439,9 +1566,29 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags)
                }
        }
 
+       if (force_restore) {
+               /*
+                * The HW doesn't handle being told to restore the current
+                * context very well. Quite often it likes goes to go off and
+                * sulk, especially when it is meant to be reloading PP_DIR.
+                * A very simple fix to force the reload is to simply switch
+                * away from the current context and back again.
+                *
+                * Note that the kernel_context will contain random state
+                * following the INHIBIT_RESTORE. We accept this since we
+                * never use the kernel_context state; it is merely a
+                * placeholder we use to flush other contexts.
+                */
+               *cs++ = MI_SET_CONTEXT;
+               *cs++ = i915_ggtt_offset(to_intel_context(i915->kernel_context,
+                                                         engine)->state) |
+                       MI_MM_SPACE_GTT |
+                       MI_RESTORE_INHIBIT;
+       }
+
        *cs++ = MI_NOOP;
        *cs++ = MI_SET_CONTEXT;
-       *cs++ = i915_ggtt_offset(to_intel_context(rq->ctx, engine)->state) | flags;
+       *cs++ = i915_ggtt_offset(rq->hw_context->state) | flags;
        /*
         * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
         * WaMiSetContext_Hang:snb,ivb,vlv
@@ -1509,31 +1656,28 @@ static int remap_l3(struct i915_request *rq, int slice)
 static int switch_context(struct i915_request *rq)
 {
        struct intel_engine_cs *engine = rq->engine;
-       struct i915_gem_context *to_ctx = rq->ctx;
-       struct i915_hw_ppgtt *to_mm =
-               to_ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
-       struct i915_gem_context *from_ctx = engine->legacy_active_context;
-       struct i915_hw_ppgtt *from_mm = engine->legacy_active_ppgtt;
+       struct i915_gem_context *ctx = rq->gem_context;
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
+       unsigned int unwind_mm = 0;
        u32 hw_flags = 0;
        int ret, i;
 
        lockdep_assert_held(&rq->i915->drm.struct_mutex);
        GEM_BUG_ON(HAS_EXECLISTS(rq->i915));
 
-       if (to_mm != from_mm ||
-           (to_mm && intel_engine_flag(engine) & to_mm->pd_dirty_rings)) {
-               trace_switch_mm(engine, to_ctx);
-               ret = to_mm->switch_mm(to_mm, rq);
+       if (ppgtt) {
+               ret = load_pd_dir(rq, ppgtt);
                if (ret)
                        goto err;
 
-               to_mm->pd_dirty_rings &= ~intel_engine_flag(engine);
-               engine->legacy_active_ppgtt = to_mm;
-               hw_flags = MI_FORCE_RESTORE;
+               if (intel_engine_flag(engine) & ppgtt->pd_dirty_rings) {
+                       unwind_mm = intel_engine_flag(engine);
+                       ppgtt->pd_dirty_rings &= ~unwind_mm;
+                       hw_flags = MI_FORCE_RESTORE;
+               }
        }
 
-       if (to_intel_context(to_ctx, engine)->state &&
-           (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) {
+       if (rq->hw_context->state) {
                GEM_BUG_ON(engine->id != RCS);
 
                /*
@@ -1543,35 +1687,38 @@ static int switch_context(struct i915_request *rq)
                 * as nothing actually executes using the kernel context; it
                 * is purely used for flushing user contexts.
                 */
-               if (i915_gem_context_is_kernel(to_ctx))
+               if (i915_gem_context_is_kernel(ctx))
                        hw_flags = MI_RESTORE_INHIBIT;
 
                ret = mi_set_context(rq, hw_flags);
                if (ret)
                        goto err_mm;
+       }
 
-               engine->legacy_active_context = to_ctx;
+       if (ppgtt) {
+               ret = flush_pd_dir(rq);
+               if (ret)
+                       goto err_mm;
        }
 
-       if (to_ctx->remap_slice) {
+       if (ctx->remap_slice) {
                for (i = 0; i < MAX_L3_SLICES; i++) {
-                       if (!(to_ctx->remap_slice & BIT(i)))
+                       if (!(ctx->remap_slice & BIT(i)))
                                continue;
 
                        ret = remap_l3(rq, i);
                        if (ret)
-                               goto err_ctx;
+                               goto err_mm;
                }
 
-               to_ctx->remap_slice = 0;
+               ctx->remap_slice = 0;
        }
 
        return 0;
 
-err_ctx:
-       engine->legacy_active_context = from_ctx;
 err_mm:
-       engine->legacy_active_ppgtt = from_mm;
+       if (unwind_mm)
+               ppgtt->pd_dirty_rings |= unwind_mm;
 err:
        return ret;
 }
@@ -1580,7 +1727,7 @@ static int ring_request_alloc(struct i915_request *request)
 {
        int ret;
 
-       GEM_BUG_ON(!to_intel_context(request->ctx, request->engine)->pin_count);
+       GEM_BUG_ON(!request->hw_context->pin_count);
 
        /* Flush enough space to reduce the likelihood of waiting after
         * we start building the request - in which case we will just
@@ -2006,11 +2153,11 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
        intel_ring_init_semaphores(dev_priv, engine);
 
        engine->init_hw = init_ring_common;
-       engine->reset_hw = reset_ring_common;
+       engine->reset.prepare = reset_prepare;
+       engine->reset.reset = reset_ring;
+       engine->reset.finish = reset_finish;
 
        engine->context_pin = intel_ring_context_pin;
-       engine->context_unpin = intel_ring_context_unpin;
-
        engine->request_alloc = ring_request_alloc;
 
        engine->emit_breadcrumb = i9xx_emit_breadcrumb;
@@ -2074,16 +2221,6 @@ int intel_init_render_ring_buffer(struct intel_engine_cs *engine)
        if (ret)
                return ret;
 
-       if (INTEL_GEN(dev_priv) >= 6) {
-               ret = intel_engine_create_scratch(engine, PAGE_SIZE);
-               if (ret)
-                       return ret;
-       } else if (HAS_BROKEN_CS_TLB(dev_priv)) {
-               ret = intel_engine_create_scratch(engine, I830_WA_SIZE);
-               if (ret)
-                       return ret;
-       }
-
        return 0;
 }